/**
 * @module NGS.plugins
 * @description NGS 系统插件
 * @author Lori
 */
"use strict";

/**
 * @class Chat
 * @description 提供坐席聊天功能
 */
define(['js/lib/async.min', 'js/plugins/chat/chat.common', 'js/plugins/chat/i18n/chat.' + $E.lang, 'js/plugins/chat/jquery.rateyo.min'], function (async, $COMM, i18n) {
    /**
     * @class Chat
     * @constructor
     * @param {object} project 项目对象
     * @param {dom} container 插件装载的容器
     */
    var chatServerAddr,
      chatMonitorPull = false,
      chatMonitorPullTime = 0,
      chatServerHost,
      chatServerName,
      _messageId = 0,
      EMOTION = $COMM.EMOTION,
      ICONS = $COMM.ICONS,
      REQUEST_STATUS = $COMM.REQUEST_STATUS,
      CHAT_REQUEST_TYPE = $COMM.CHAT_REQUEST_TYPE,
      USER_STATUS = $COMM.USER_STATUS,
      CLIENT_TYPE = $COMM.CLIENT_TYPE,
      NOTICE_TYPE = $COMM.NOTICE_TYPE,
      MESSAGE_TYPE = $COMM.MESSAGE_TYPE,
      Tools = $COMM.Tools,
      SoundManager = $COMM.SoundManager,
      Robot = $COMM.Robot;

    let currentSessionId = 0
    let currentStaffId = 0
    let searchMessagePull = null
    let takeOverArray = []
    let refreshFlag = false

    /**
     * 用户对象
     * @param id
     * @param firstName
     * @param lastName
     * @param alias
     * @param headImg
     * @constructor
     */
    function User(id, firstName, lastName, alias, headImg) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.alias = alias;
        this.headImg = headImg;
    }

    /**
     * 会话对象
     * @param id
     * @constructor
     */
    function Session(id) {
        this.id = id;
        this.clientId = -1;
        this.client = {};
        this.preMsgUserId = "";
        this.previewMessage = "";
        this.allMessages = [];
        this.active = true;  //boolean: if the session is still active
        this.creationTime = new Date().getTime();
        this.endTime;
        this.timeLapse = 0;
        this.hasPushedRating = false;
        this.serviceAccountId = "";
        this.serviceAccountName = "";
        this.lastUserMessageReceivedTime = -1;
        this.lastAutoReplyMessageTime = -1;
        this.lastAgentMessageSentTime = -1;
        this.userInWaiting = false;
        this.autoReplyMessageTimes = 0;
        this.queueId = -1;
        this.queueName = "";
        this.users = {};
        this.userCount = 0;
        this.hasCloseAFK = false;
        this.customNotice;
        this.permFlag = 0;
        this.pushRatingCount = 0;
        this.firstReply = false;
        this.languageTo = '';
    }

    /**
     * 消息对象
     * @param id
     * @param userId
     * @param userName
     * @param text
     * @param formattedTime
     * @param icon
     * @param revokeFlag
     * @param type
     * @constructor
     */
    function Message(id, userId, userName, text, translate, stateId, formattedTime, icon, revokeFlag, type) {
        this.id = id;
        this.userId = userId;
        this.userName = userName;
        this.text = text;
        this.translate = translate;
        this.stateId = stateId;
        this.formattedTime = formattedTime;
        this.icon = icon;
        this.revokeFlag = revokeFlag || 0;
        this.type = type || 0;// 0普通消息, 1系统消息, 2表示系统自动发送的消息
    }

    /**
     *  #########  聊天插件主类  #########
     * @param project
     * @param container
     * @param parameters
     * @returns {ChatMonitor}
     * @constructor
     */
    var ChatMonitor = function (project, container, parameters) {
        // 动态页面传入值
        currentSessionId = parameters.sessionId
        currentStaffId = parameters.staffId
        if (searchMessagePull) {
            clearTimeout(searchMessagePull)
        }
        var c = this,
          //最后一次pull时间
          lastPullTime,
          //所有会话id数组
          sessionIdsArr = [],
          //所有会话数组
          sessionsMap = {},
          //所有请求id数组
          requestIdsArr = [],
          // 所有的消息
          allMessages = [],
          //当前请求id
          currentRequestId,
          //当前会话id
          lastCreatedSessionId,
          currentCustomerGuid,
          currentTIR,
          allowCloseSessionDirectly = true,
          sendType = 0,
          chatStyle,
          headImgBaseUrl = location.pathname.substring(0, location.pathname.indexOf('/', 1)) + '/fs/get?file=',
          soundManager,
          tools,
          enableClientRating = false,
          currentVoiceAudio,
          showSessionButtons = false,
          showTypeOnName = false,
          chatExclusion = false,
          sinkAfterEnds = false,
          requestTabs,
          lastChattingTimeThreshold,
          //请求进度条计时器, 多个请求，以请求id为key
          requestProgressTimer = {},
          //定时更新用户等待时长计时器
          userWaitingTimer,
          //用户状态超时定时器
          userStatusTimer,
          //输入提示显隐的计时器
          typingTimer,
          //输入提示增强效果计时器
          typingEffectTimer,
          //是否启用建议搜索
          suggestionSearchEnabled = false,
          //个性配置中是否开启建议搜索
          customSuggestionEnabled = true,
          //超过多少个字符后，就不去给出建议
          suggestionMaxWordLength = 10,
          //建议检索计时器，避免短时间内发出大量请求
          suggestionSearchTimer,
          //上一次查找建议时候搜的内容
          lastSearchContentForSuggestion,
          //每次获取历史消息的条数
          countForFetchingPreviousMessage = 30,
          //客户相关缓存信息
          clientCache = {},
          topSessionOnNewMessage = 1,
          //是否卡其脏词扫描
          dirtyWordsScanEnabled = false,
          // 是否开启关键词扫描
          highlightWordsScanEnable = false,
          //是否允许消息撤回
          messageRevokeEnabled = false,
          checkPullTimer,
          // 是否开启辅助机器人自动应答
          robotAutoAnswerEnabled = false,
          //是否开启新消息声音提醒
          newMassageSoundEnabled = false,
          // 是否开启发送消息的同时自动翻译内容
          translateAutoEnabled = false,
          // 是否开启不用提示直接推送满意度
          pushRatingDirectly = false,
          // 是否允许跨工作组转接
          enableCrossWorkgroupTransfer = false,
          // 是否启用splitter
          disableSplitter = false,
          // 发送typingNotice的最小间隔时间（秒）
          typingNotificationDelay = 10,
          // 上一次发送typingNotice的时间
          lastTypingNotificationTime = 0,
          // 消息展示样式类型
          messageBubbleStyle = undefined,
          // 新消息来时候是否通知框架
          newMessageNotifyEnabled = false,
          // 发送消息最长限制
          maxSendingWordLength = 0,
          // 系统自动发送通知消息是否需要提醒，默认不提醒
          systemNoticeNotify = false,
          //用来限制客户发送了消息，坐席没有回复之后，自动发送消息内容的展示次数 0 表示没有限制， 大于 0 的表示限制的消息发送次数
          sysAutoReplyMessageTimes = 0,
          // 是否禁止上传
          uploadDisabled = false,
          // 是否展示坐席辅助小浮屏
          showAgentAssistIframe = undefined,
          // 粘贴图片或者截图后，图标是弹出是否发送还是进入输入框
          editImageAfterPaste = false,
          //含有敏感词的内容是否禁止发送
          chatSensitiveSend = 0;


        this.project = project;
        Robot.init(project);
        this.container = container;
        this.staff;
        this.configs;
        this.logined = false;
        this.currentUserStatus = USER_STATUS.OFFLINE;
        this.queues = [];
        // 选中队列下所有非离线坐席列表
        this.agentList = [];
        this.worker = new Worker($E.url + '/js/plugins/chat/chat.worker.js?v=' + $E.ver);
        // 消息是否正在发送中
        this.sending = false;
        this.userStatus = {};
        this.parameters = parameters || {};

        //chat服务地址
        chatServerAddr = project.getParam('CHATAD')
        // chatServerAddr = 'https://localhost:448/webchat'
        // 网聊监控pull间隔时间参数
        chatMonitorPullTime = project.getParam('CHMPUL')
        chatMonitorPull = Boolean(chatMonitorPullTime)
        //是否允许直接关闭会话，如果不允许则会发出关闭消息
        allowCloseSessionDirectly = project.getParam('CTACSD') == 0 ? false : true;
        //是否允许客户评级
        enableClientRating = getIntParam(project, 'CACREN') === 1;
        //是否显示转接 邀请 转接组 这些按钮到聊天界面右上角
        showSessionButtons = getIntParam(project, 'CHASSB') === 1;
        //CHTSTY 表示 chat插件使用的样式
        chatStyle = project.getParam('CHTSTY') || 'chat';
        //是否在名字上显示客户来源类型
        showTypeOnName = getIntParam(project, 'CHATON') === 1;
        //是否与软电话互斥
        chatExclusion = getIntParam(project, 'CHAECS') === 1;
        //结束的会话是不是要下沉到tab的底部
        sinkAfterEnds = getIntParam(project, 'CHASAE') === 1;
        //客户发送消息作息未回复，自动推送消息的次数限制
        sysAutoReplyMessageTimes = getIntParam(project, 'CHARMT') || 0;
        //上一个消息收到到现在多长时间，需要给出警示颜色（单位秒）
        lastChattingTimeThreshold = project.getParam('CHALTT');
        //是否允许坐席消息撤回，允许的话，新发消息右击可以实现消息撤回操作
        messageRevokeEnabled = getIntParam(project, 'CHAMRV') === 1;
        // 是否允许跨工作组发起转接会议请求
        enableCrossWorkgroupTransfer = getIntParam(project, 'CHACWT') === 1;
        // 是否关闭splitter
        disableSplitter = getIntParam(project, 'CHADSP') === 1;
        // 消息气泡展示类型
        messageBubbleStyle = project.getParam('CHAMBS');
        // 收到新消息后是否发出事件通知框架
        newMessageNotifyEnabled = getIntParam(project, 'CHANNM') === 1;
        //禁用词消息是否禁止发送,为true则禁止发送
        chatSensitiveSend = getIntParam(project, 'CHASWD')===1
        //是否启用建议搜索功能
        let CHASSE = project.getParam('CHASSE');
        if (CHASSE) {
            try {
                CHASSE = JSON.parse(CHASSE);
                suggestionSearchEnabled = CHASSE.enabled;
                if (!isNaN(CHASSE.maxWordLength)) {
                    suggestionMaxWordLength = CHASSE.maxWordLength;
                }
            } catch (e) {
            }
        }
        // 默认表情是否需要隐藏： 1表是隐藏qq表情，2表示隐藏emoji表情， 3表示都隐藏, 4表示qq表情和emoji表情位置互换
        let CHAEMO = $F.parseInt(project.getParam('CHAEMO'));
        // chat中ajax请求最大重试次数，默认3次
        let CHAMRT = project.getParam('CHAMRT');
        // 包装url的逻辑，是不是需要包装，是否符合黑白名单
        let CHAWUR = project.getParam('CHAWUR');
        if (CHAWUR) {
            try {
                CHAWUR = JSON.parse(CHAWUR);
            } catch (e) {
            }
        }
        // 是否开启高亮词扫描
        highlightWordsScanEnable = getIntParam(project, 'CHAHWS') === 1;
        // 最大发送消息长度，默认未0表示不限制
        maxSendingWordLength = project.getParam('CHAMSL') || 0;
        // 系统通知是否需要提醒
        systemNoticeNotify = getIntParam(project, 'CHASNN') === 1;
        // 是否屏蔽上传
        uploadDisabled = getIntParam(project, 'CHAAUD') === 1;
        //是否展示坐席辅助的小浮屏的iframe {url： "", iconUrl: "", style: {}}
        var showAgentAssistIframeStr = project.getParam('CHAIFM');
        if (showAgentAssistIframeStr) {
            try {
                let showAgentAssistIframeObj = JSON.parse(showAgentAssistIframeStr);
                showAgentAssistIframe = {
                    id: 'agentAssistWindow',
                    url: showAgentAssistIframeObj.url,
                    style: showAgentAssistIframeObj.style,
                    imageUrl: showAgentAssistIframeObj.imageUrl
                };
            } catch (e) {
                $F.log("Chat", "Parse CHAIFM error: " + showAgentAssistIframeStr);
            }
        }
        editImageAfterPaste = getIntParam(project, 'CHAIAP') === 1;

        //测试环境中需要设置的一些配置
        if (location.hostname === "127.0.0.1" && (location.port === "8099" || location.port === "8080" || location.port === "8088") || location.hostname === "192.168.2.80" && location.port === "8080") {
            // chatServerAddr = 'http://' + location.hostname + ':8099' + '/webchat';
            // chatServerAddr = 'http://' + location.hostname + ':' + (location.port === "8099" ? '8099' : '8980') + '/webchat';
            chatServerAddr = 'http://' + location.hostname + ':8088/webchat';
            showSessionButtons = true;
            enableClientRating = false;
            chatStyle = 'chat-white';
            //chatExclusion = true;
            //project.params['CHAECS'] = '1';
            messageRevokeEnabled = true;
            lastChattingTimeThreshold = 10;
            sinkAfterEnds = true;
            suggestionSearchEnabled = true;
//            require(['js/elasticsearch.client' + $E.jsv], function(esc){
//    			esc.init({"hosts":"127.0.0.1:9200","log":"trace"}, function(){
//
//    			}, function(error){
//    				console.error(error);
//    			});
//    			project.esc = esc;
//            });
            CHAEMO = 4;
            enableCrossWorkgroupTransfer = true;
            messageBubbleStyle = 'dc';
            highlightWordsScanEnable = true;
            CHAWUR = {
                nowrap: false,
                whiteList: [],
                blackList: ["www.elitecrm.com"]
            };
            editImageAfterPaste = true;
        }
        if (!chatServerAddr) {
            $F.alert(i18n.error.chatServerCheckAlert);
            return;
        }
        chatServerHost = chatServerAddr.substring(0, chatServerAddr.lastIndexOf("/"));
        chatServerName = chatServerAddr.substring(chatServerAddr.lastIndexOf("/"), chatServerAddr.length);
        soundManager = new SoundManager(chatServerAddr);
        tools = new Tools(chatServerAddr, CHAMRT);

        //调用服务接口
        var callService = function (params, retry) {
            if (params && params.url) {
                params.url = tools.chatServerAddr + "/" + params.url;
            }
            return tools.callService(params, (retry ? 0 : undefined));
        };

        var getPropertyByQueue = function (property, queueId, lang, defaultValue) {
            return new Promise(resolve => {
                let key = queueId;
                if (lang) {
                    key = queueId + lang;
                }
                if (c.configs.queueConfigs[key]) {
                    resolve(c.configs.queueConfigs[key][property] || defaultValue);
                } else {//没有此队列相关属性，重新获取
                    tools.callService({
                        data: {
                            requestType: "fetchQueueConfig",
                            queueId: queueId,
                            lang: lang
                        }
                    }).then(data => {
                        if (data.status === 'success') {
                            c.configs.queueConfigs[key] = data.config;
                            resolve(c.configs.queueConfigs[key][property] || defaultValue);
                        } else {
                            resolve(defaultValue);
                        }
                    }).fail(() => {
                        resolve(defaultValue);
                    });
                }
            });
        };

        //聊天插件是否隐藏
        function chatPanelIsHidden() {
            return $('.chat-monitor', container).is(":hidden") || ($('.chat', container).width() === 0);
        };

        function pullFromServer(c) {
            var sessionIds = [], sessionPerms = [];
            $.each(sessionsMap, function (key, sessionCur) {
                if (sessionCur.active && sessionCur.id > 0) {
                    sessionIds.push(sessionCur.id);
                    sessionPerms.push(sessionCur.permFlag);
                }
            });
            var pullSendInfoJSON = JSON.stringify({
                "senderId": c.configs.agentId,
                "chatRequestIdsFromUser": requestIdsArr,
                sessionIds: sessionIds,
                sessionPerms: sessionPerms
            });

            lastPullTime = new Date().getTime();
            $F.log('ChatMonitor - pull', 'Start pull: ' + pullSendInfoJSON);
            callService({
                data: {
                    requestType: "pull",
                    data: pullSendInfoJSON
                }
            }).done(function (data) {
//        		try {
                if (!data) {
                    $F.err("ChatMonitor - pull", "ERROR: Network or Server fault");
                } else {
                    if (data === 'retry') {

                    } else if (data === 'NOT_LOGGED_IN') {
                        $F.alert(i18n.error.notLoggedInAlert);
                        c.closeChat();
                    } else {
                        processJSONPullReturn(data);
                    }
                }
//        		} catch (e) {
//        			$F.log('Chat - pullFromServer', 'Error: ' + JSON.stringify(e));
//        		}
            }).always(function () {
                c.worker.postMessage({
                    cmd: 'doPull',
                    params: {
                        timeout: c.configs.timeoutForPull
                    }
                });
            });
        }

        /**
         * 指定当前session里的客户等待状态，并且在设置状态的时候设置发送消息的次数，或者是重置发送消息次数
         * @param session
         */
        function setUserInWaiting(session, userInWaiting) {
            session.userInWaiting = userInWaiting;
            //如果是设置当前客户状态,就重置发送的次数为0
            session.autoReplyMessageTimes = 0;
        }

        function processJSONPullReturn(jsonResponse) {
            console.log('ChatMonitor - processJSONPullReturn', JSON.stringify(jsonResponse));
            if (jsonResponse.status === 'success') {
                let receivedInfo = jsonResponse.pullResponse;

                //process session data
                let sessions = receivedInfo.sessions;
                if (sessions && sessions.length > 0) {
                    for (let sessionIndex = 0; sessionIndex < sessions.length; sessionIndex++) {
                        let session = sessions[sessionIndex], sessionId = session.id;
                        let thisSession = sessionsMap["session" + sessionId];
                        if (!thisSession) {
                            //会话转接时候，如果直接关闭了转接成功的会话，这里会获取不到这个thisSession对象，所以加了保护
                            if (!session.session) continue;
                            // 如果有这个session.session 表示要新建这个会话
                            let queueId = session.session.queueId,
                              queueName = session.session.queueName,
                              sessionParams = session.session.sessionParams,
                              client = session.session.client;
                            // 如果本地没有此会话，可能需要新建这个会话item
                            let newSession = createSession(sessionId, client, queueId, queueName, sessionParams);
                            newSession.permFlag = session.session.permFlag;
                            sessionsMap["session" + sessionId] = newSession;
                            sessionIdsArr[sessionIdsArr.length] = sessionId;
                            lastCreatedSessionId = "session" + sessionId;
                            setupClientDisplayName(client);
                            setupClientIcon(client);
                            thisSession = newSession;
                        }
                        let sessionNotices = session.sessionNotices;
                        if (sessionNotices) {
                            for (let noticeIndex = 0; noticeIndex < sessionNotices.length; noticeIndex++) {
                                let notice = sessionNotices[noticeIndex];
                                let noticeMessage = notice.message;
                                let noticeType = notice.type;
                                //除了typing和custom 其他notice消息都要添加的会话消息中
                                if (noticeType != NOTICE_TYPE.TYPING && noticeType != NOTICE_TYPE.CUSTOM) {
                                    addMessageToSession(sessionId, {
                                        id: "-1",
                                        name: null
                                    }, {text: formatFeedbackMessage(noticeMessage), type: MESSAGE_TYPE.SYSTEM});
                                }
                                if (noticeType == NOTICE_TYPE.TYPING) { // 输入提示
                                    if (sessionId == currentSessionId) {
                                        noticeMessage = noticeMessage.split('_')[1];
                                        setTypingNotice(noticeMessage);
                                    }
                                } else if (noticeType == NOTICE_TYPE.TRACK_CHANGE) { // 轨迹变化提示

                                } else if (noticeType === NOTICE_TYPE.REVOKE_MESSAGE) { // 消息撤回
                                    console.log('Revoke message: ' + noticeMessage)
                                } else if (noticeType == NOTICE_TYPE.CUSTOM) { // 自定义notice
                                    thisSession.customNotice = noticeMessage;//保存到session的属性上
                                    $F.log('ChatMonitor - processJSONPullReturn', 'Fire CUSTOM_NOTICE to session[' + sessionId + ']: ' + noticeMessage);
                                    notifyProjectEvent($CONST.ChatEvent.CUSTOM_NOTICE, {
                                        currentSessionId: currentSessionId,
                                        sessionId: sessionId,
                                        message: noticeMessage
                                    });
                                } else {
                                    if (noticeType == NOTICE_TYPE.USER_LEFT_NOTICE) {
                                        thisSession.userCount--;
                                        if (sessionId == currentSessionId) {
                                            $('.session_hd .title_name', container).html(thisSession.client.name + ((thisSession.userCount > 2) ? '(' + thisSession.userCount + ')' : ''));
                                        }
                                    }
                                    if (sessionId == currentSessionId) {
                                        appendTextToDiv(formatFeedbackMessage(noticeMessage));
                                    }
                                }
                            }
                        }

                        if (sessionId == currentSessionId) {
                            refreshPreMessage(session.tempMessage, sessionId);
                        }

                        thisSession.previewMessage = session.tempMessage;

                        let newMessages = session.newMessages;
                        let preMsgUserId = thisSession.preMsgUserId;
                        for (let messageIndex = 0; messageIndex < newMessages.length; messageIndex++) {
                            let message = newMessages[messageIndex];
                            let text = message.text;
                            if (text) {
                                text = tools.parseDisplayContent(text);
                                if (!text) {
                                    continue;
                                }
                                // 新消息收到后发出事件通知框架
                                if (newMessageNotifyEnabled) {
                                    notifyProjectEvent($CONST.ChatEvent.NEW_MESSAGE_RECEIVED || 'NEW_MESSAGE_RECEIVED', {
                                        sessionId: sessionId,
                                        message: message
                                    });
                                }

                                var userId = message.userId;
                                var userName = message.userName;
                                //判断客户是不是有变更，userType必须是1也就是客户的时候才考虑
                                if (userId != thisSession.clientId && message.userType == 1) {
                                    updateClientForSession(thisSession, userId, userName);
                                }


                                if (c.highlightWords) {
                                    c.highlightWords.forEach(function (hw) {
                                        var hwReg = new RegExp(hw, 'g');
                                        text = text.replace(hwReg, '<span class="dw-highlight">' + hw + '</span>');
                                    });
                                }

                                var newMessage = addMessageToSession(sessionId, {
                                    id: userId,
                                    name: userName
                                }, {
                                    id: message.id,
                                    text: text,
                                    translate: message.translateMessage
                                }, Tools.getFormattedTime(message.postTime || new Date().getTime(), 1));
                                if (message.extra) newMessage.extra = message.extra;
                                // 每条新消息都发出通知
                                showMessageOnItem(sessionId, text);
                                if (sessionId == currentSessionId) {
                                    refreshPreMessage();
                                    removeTypingNotice();
                                    $F.log("ChatMonitor - processJSONPullReturn", "pull message " + userId + " : " + text);
                                    var displayMessage = getDisplayMessage(newMessage, thisSession);
                                    appendTextToDiv(displayMessage);
                                    //setLastMessageReceivedTime ('最后一条消息时间 ' + currentTime3());
                                }
                                newMassageSoundEnabled && soundManager.play('newMessageSound');
                                preMsgUserId = userId;

                                if (message.userType == 1) {
                                    if (!thisSession.userInWaiting) {
                                        setUserInWaiting(thisSession, true);
                                        thisSession.lastUserMessageReceivedTime = new Date().getTime();
                                    } else {
                                        thisSession.autoReplyMessageTimes = 0;
                                    }
                                    thisSession.lastAutoReplyMessageTime = new Date().getTime();
                                    thisSession.hasUserNoResponseNotified = false;
                                }
                            }
                        }
                        thisSession.preMsgUserId = preMsgUserId;

                        if (session.ifShouldEnd) {
                            if (thisSession && thisSession.active) {
                                var feedback = i18n.feedback.clientLoggedOut;
                                addMessageToSession(sessionId, {
                                    id: "-1",
                                    name: null
                                }, {text: formatFeedbackMessage(feedback), type: MESSAGE_TYPE.SYSTEM});
                                thisSession.active = false;
                                thisSession.endTime = new Date().getTime();
                                thisSession.previewMessage = '';
                                searchSessionMessage(null, false, currentSessionId)
                                $F.log('ChatMonitor - processJSONPullReturn', 'Session shouldEnd, set session ' + sessionId + ' active false');
                                if (sessionId == currentSessionId) {
                                    appendTextToDiv(formatFeedbackMessage(feedback));
                                }
                                // FixMe
                                disableSession(sessionId);
                                refreshSessionStat();
                                sinkSession(sessionId);
                                checkReservedStatusWhenSessionEnd();
                            }
                        }
                    }//end for session in sessions
                }//end if sessions

                // 坐席实时查看排队人数
                if (c.configs.agentRealtimeQueueMonitorEnable) {
                    if (receivedInfo.monitorInfo) {
                        $('.stat_info .queue_waiting_requests', container).text(receivedInfo.monitorInfo.waitingRequests || 0);
                    }
                }
            } else if (jsonResponse.status === 'relogined') {
                alert(i18n.error.reloggedInAlert);
                c.closeChat();
            }
        }

        function sendRequestResponse(requestId, msg) {
            var sentInfoJSON = JSON.stringify({
                actionType: "respondToRequest",
                senderId: c.configs.agentId,
                senderName: c.staff.displayName,
                chatRequestId: requestId,
                message: msg
            });

            $F.log("ChatMonitor - sendRequestResponse", sentInfoJSON);
            callService({
                data: {
                    requestType: "send",
                    data: sentInfoJSON
                },
                success: data => {
                    processRespondToRequestReturn(data);
                }
            }, true).fail(function (e) {
                if (msg === 'yes') {
                    if (e.statusText === 'timeout') {
                        // 如果超时了，那么尝试再去请求服务器看这个坐席现在有哪些会话
                        recoverSession(requestId);
                    }
                }
            });
        }

        function processRespondToRequestReturn(jsonResponse) {
            console.log('ChatMonitor - processRespondToRequestReturn', JSON.stringify(jsonResponse));
            if (jsonResponse.status === 'success') {
                var sendResponse = jsonResponse.sendResponse;
                if (sendResponse) {
                    var result = sendResponse.result;
                    var feedbackMessage = sendResponse.feedbackMessage;
                    if (result === 1 || sendResponse.ifSucceed) {//ifSucceed已经不使用，这里为了兼容老的chat服务
                        //接起会话成功如果是当前的聊天界面是隐藏的，那么需要自动展示出来
                        var isCurrentSession = false,
                          sessionId = sendResponse.sessionId,
                          clientId = sendResponse.clientId,
                          queueId = sendResponse.queueId,
                          queueName = sendResponse.queueName,
                          sessionParams = sendResponse.sessionParams || {},
                          usersInSession = sendResponse.usersInSession,
                          eventGuid = sendResponse.eventGuid,
                          client = sendResponse.client,
                          from = sendResponse.from;
                        setupClientIcon(client);
                        setupClientDisplayName(client);
                        if (c.configs.autoCloseTabInMultiRequest) {
                            $.each(sessionsMap, function (i, session) {
                                if (session.active && session.clientId === clientId && session.queueId == queueId && sessionsMap["session" + sessionId] === undefined) {
                                    $F.log("ChatMonitor - processRespondToRequestReturn", "removeTabAndSession: " + session.id + " cause a new request is coming from the same client.");
                                    removeTabAndSession(session.id);
                                }
                            });
                        }

                        if (sessionsMap["session" + sessionId] === undefined) {
                            var newSession = createSession(sessionId, client, queueId, queueName, sessionParams, eventGuid);
                            sessionsMap["session" + sessionId] = newSession;
                            sessionIdsArr[sessionIdsArr.length] = sessionId;
                        } else { //session already exists: this happens when the session was transferred to other agent before
                            var tab = $('#sessionTab_' + sessionId, container),
                              curSession = sessionsMap["session" + sessionId];
                            if (tab.length === 0) {
                                sessionIdsArr[sessionIdsArr.length] = sessionId; //if tab was destroyed, then the sessionId was removed too
                            } else {
                                enableSession(sessionId);
                                isCurrentSession = true;
                            }
                            curSession.active = true;
                            curSession.userCount = 0;
                        }
                        var sessionCur = sessionsMap["session" + sessionId];
                        lastCreatedSessionId = "session" + sessionId;

                        var historySessions = sendResponse.historySessions;
                        if (historySessions) {
                            $.each(historySessions, function (i, hs) {
                                $.each(hs.newMessages, function (j, message) {
                                    var text = message.text;
                                    if (!Robot.isRobot(message.userId)) {//非机器人时候才需要parse
                                        text = tools.parseDisplayContent(text);
                                    } else {
                                        text = Robot.parseRobotMessage(text, message.userId);
                                    }
                                    if (text) {
                                        addMessageToSession(sessionId, {
                                            id: message.userId,
                                            name: message.userName,
                                            icon: message.icon
                                        }, {
                                            text: text,
                                            translate: message.translateMessage,
                                            revokeFlag: message.revokeFlag,
                                            history: true
                                        }, Tools.getFormattedTime(message.postTime));
                                    }
                                });
                                var sessionEndTime = '';
                                if (hs.sessionInfo && hs.sessionInfo.endTime) {
                                    sessionEndTime = ' [' + new Date(hs.sessionInfo.endTime).format('yyyy-MM-dd hh:mm:ss') + ']';
                                }
                                addMessageToSession(sessionId, {
                                    id: "-1",
                                    name: null
                                }, {
                                    text: '<div class="notice"><span class="line">————————</span>' + i18n.session + hs.id + sessionEndTime + '<span class="line">————————</span></div>',
                                    history: true,
                                    type: MESSAGE_TYPE.SYSTEM
                                });
                            });
                        }

                        addMessageToSession(sessionId, {
                            id: "-1",
                            name: null
                        }, {text: formatFeedbackMessage(feedbackMessage), type: MESSAGE_TYPE.SYSTEM});
                        $.each(usersInSession, function (i, user) {
                            sessionCur.users[user.id] = new User(user.id, user.firstName, user.lastName, user.alias, user.headImg);
                            sessionCur.userCount++;
                        });


                        // 允许音视频
                        getPropertyByQueue('allowAudioVisual', queueId).then(msg => {
                            if (msg && msg.appId) {
                                if (msg.type && msg.type === 'tencent') {
                                    require(['js/plugins/chat/chat.tencent.meeting'], function (Meeting) {
                                        Meeting.loadTencentMeet(msg, sessionId, sessionCur.client.name, container);
                                    });
                                } else {
                                    require(['js/plugins/chat/chat.meeting'], function (Meeting) {
                                        $('.chat-monitor .chat_audio', container).show();
                                        $('.chat-monitor .chat_video', container).show();
                                        Meeting.loadMeet(msg, container);
                                    });
                                }
                            } else {
                                $('.chat-monitor .chat_audio', container).hide();
                                $('.chat-monitor .chat_video', container).hide();
                            }
                        });

                        refreshSessionStat();
                    } else { //failed
                        $F.log("ChatMonitor - processRespondToRequestReturn", "request " + sendResponse.chatRequestId + " failed: " + feedbackMessage);
                        $F.notify(i18n.error.requestAlreadyClosed, 0);
                    }
                }
            }
        }


        function addMessageToSession(sessionId, user, msg, time) {
            var userId = user.id,
              userName = user.name,
              icon = user.icon,
              formattedTime = time || new Date().format('YYYY-MM-dd HH:mm:ss'),
              msgText = msg,
              msgId = 'i' + _messageId++,
              msgRevokeFlag = 0,
              translate = '',
              stateId = '',
              msgType = 0,
              hisMsg = false;
            if (typeof msg === 'object') {
                msgText = msg.text;
                translate = msg.translate || '';
                stateId = msg.stateId || '';
                msgId = msg.id || msgId;
                msgRevokeFlag = msg.revokeFlag || msgRevokeFlag;
                hisMsg = msg.history || hisMsg;
                msgType = msg.type || msgType;
            }
            var message = new Message(msgId, userId, userName, msgText, translate, stateId, formattedTime, icon, msgRevokeFlag, msgType);
            allMessages.push(message);
            if (!hisMsg && (systemNoticeNotify && msg.systemNotice || !msg.systemNotice)) {
                //显示最新消息时间
                // $('#sessionTab_' + sessionId + ' .ext .attr', container).html(Tools.getFormattedNowTime());
                let sessionCur = sessionsMap['session' + sessionId];
                if (userId === sessionCur.clientId) {
                    if (sessionCur.sessionParams && sessionCur.sessionParams.robotEngine) {
                        var robotEngine = sessionCur.sessionParams.robotEngine;
                        var allowFrom = true;
                        var fromCur = sessionCur.client.from;
                        if (fromCur && robotEngine.extra && robotEngine.extra.from) {
                            var fromAllowsArr = robotEngine.extra.from;
                            if ($.isArray(fromAllowsArr) && fromAllowsArr.length > 0 && $.inArray(fromCur, fromAllowsArr) === -1) {
                                allowFrom = false;
                            }
                        }
                        $F.log('ChatMonitor - searchRobot', robotEngine);
                        if (message.robotResponse === undefined) {
                            if (robotEngine.agentSearchFlag === 1 && allowFrom) {
                                //判断当前类型是使用什么形式进行辅助回答的连接
                                var useWebSocket = Robot.userWebSocket(robotEngine.type);
                                $F.log('ChatMonitor - searchRobot use webScoket ', useWebSocket);
                                if (useWebSocket) {
                                    sessionCur.lastClientMessage = message;
                                    Robot.doSearch(sessionId, msgText, robotEngine);
                                } else {
                                    //查询机器人
                                    callService({
                                        data: {
                                            requestType: "robotSearch",
                                            sessionId: sessionId,
                                            message: msgText
                                        }
                                    }).done(function (data) {
                                        if (data.status === 'success') {
                                            if (robotAutoAnswerEnabled) {
                                                var richText = false;
                                                if (robotEngine.richText) richText = robotEngine.richText;
                                                var robotAnswer = Robot.parseRobotMessageForAgentAssist(msgText, data.result, robotEngine, true, richText);
                                                if (robotAnswer) {
                                                    sendMessage(robotAnswer, sessionId);
                                                }
                                            } else {
                                                message.robotResponse = Robot.parseRobotMessageForAgentAssist(msgText, data.result, robotEngine);
                                                if (message.robotResponse) {
                                                    var curSession = sessionsMap["session" + sessionId];
                                                    appendRobotResponse(message, curSession);
                                                }
                                            }
                                        } else {
                                            message.robotResponse = null;
                                        }
                                    }).fail(function () {
                                        $F.err('ChatMonitor - robotSearch', i18n.error.getRobotResponseFailed);
                                    });
                                }
                            }
                        }
                    }

                    // 如果是客户发的消息，肯定需要提示
                    notifyMe();
                } else {
                    // 如果是坐席发的消息（这种坐席消息只可能是欢迎语之类的自动提示消息），根据配置来决定要不要提示
                    if ($F.parseInt(project.getParam('CHANMO')) !== 1) {
                        notifyMe();
                    }
                }

                if (chatPanelIsHidden() && userId !== c.configs.agentId) {
                    var reddot = $('i.web_wechat_reddot_middle', project.chatSwitch);
                    if (reddot.length > 0) {
                        var count = parseInt(reddot.html());
                        reddot.html(count + 1);
                    } else {
                        $('<i class="web_wechat_reddot_middle">1</i>').appendTo(project.chatSwitch);
                    }
                }
            }
            return message;
        }

        function appendRobotResponse(message, session) {
            let wrappedResponse = Robot.wrapResponse(message.robotResponse, function (answer) {
                if (session && session.active) {
                    $('.control_panel .content #edit-area', container).html(answer);
                }
            });

            if (session.id == currentSessionId) { // 仅当在当前会话页面上时候才直接添加信息上去
                wrapMessage(wrappedResponse);
                $('.js_message_plain[data-id=' + message.id + ']', container).html(wrappedResponse);
                scrollToBottom('.message_panel');
                //更新消息的displayMessage缓存
                var displayMessageContainer = $('<div>').append(message.displayMessage);
                $('.js_message_plain', displayMessageContainer).html(message.robotResponse);
                message.displayMessage = displayMessageContainer.html();
            }
        }

        function notifyMe() {
            if (!$E.windowOnFocus || chatPanelIsHidden()) {
                H5Utils.notifyMe(i18n.newMessageNotifyBody, i18n.newMessageNotifyTitle, 'js/plugins/chat/images/elite.gif', 'chat', function () {
                    if (!$E.windowOnFocus) {
                        window.open().close();
                        window.focus();
                    }
                    if (chatPanelIsHidden()) {
                        $E.openChatPanel();
                        $('.chat', container).show();
                    }
                });
            }
            if (!$E.windowOnFocus) {
                if (!c.blinkTitleTimer) {
                    c.blinkTitleTimer = setInterval(() => {
                        if (document.title === c.originalTitle) {
                            document.title = i18n.newMessageTitle;
                        } else {
                            document.title = c.originalTitle;
                        }
                    }, 1000)
                }
            }
        }

        /**
         * 在会话列表中 显示最新消息内容
         */
        function showMessageOnItem(sessionId, message) {
            let $htmlDom = $("<div>").append(message);
            if ($htmlDom.find("img:not(.avatar,.qqemoji,.standard-emoji,.location,.custom-emoji,div.message-imgtext .thumb,div.message-card .card-img)").length > 0) { //image
                message = i18n.itemMessage.image;
            }
            message = $('<div>').append(message).text();
            if (message) {
                message = message.replace(/</g, '&lt;').replace(/>/g, '&gt;');
                message = EMOTION.filterEmojis(message);
                var msg = $('#sessionTab_' + sessionId + ' .info .msg', container);
                if (msg.length > 0) {
                    msg.html(message);
                } else {
                    $('<p class="msg">').html(message).appendTo($('#sessionTab_' + sessionId + ' .info', container));
                }
            }
        }

        /**
         * 根据客户对象获取客户显示的名字
         */
        function setupClientDisplayName(client, newName) {
            if (newName) {
                client.name = newName;
            }
            var clientDisplayName = i18n.unknown;
            if (client.name) {
                clientDisplayName = client.name;
                if (client.nickname) {
                    clientDisplayName = clientDisplayName + '(' + client.nickname + ')';
                }
            } else if (client.nickname) {
                clientDisplayName = client.nickname;
            }

            if (showTypeOnName) {
                if (client.from) {
                    clientDisplayName = '[' + client.from + ']' + clientDisplayName;
                }
//				if (client.clientType == CLIENT_TYPE.WECHAT) {
//					clientDisplayName = clientDisplayName + '[微信]';
//				} else {
//					if ($F.equalsIgnoreCase(client.from, 'APP')) {
//						clientDisplayName = clientDisplayName + '[APP]';
//					} else if ($F.equalsIgnoreCase(client.from, 'MOBILE')) {
//						clientDisplayName = clientDisplayName + '[手机]';
//					} else if ($F.equalsIgnoreCase(client.from, 'WECHAT')) {
//						clientDisplayName = clientDisplayName + '[微信]';
//					} else {
//						clientDisplayName = clientDisplayName + '[' + client.from + ']';
//					}
//				}
            }
            client.name = clientDisplayName;
            return clientDisplayName;
        }

        /**
         * 根据客户对象获取客户显示头像
         */
        function setupClientIcon(client) {
            if (!client) {
                return ICONS.CLIENT.PC;
            }
            var icon = client.icon;
            if (!icon) {
                if (client.clientType == CLIENT_TYPE.WECHAT) {
                    icon = ICONS.CLIENT.WECHAT;
                } else {
                    if ($F.equalsIgnoreCase(client.from, 'APP')) {
                        icon = ICONS.CLIENT.PHONE;
                    } else if ($F.equalsIgnoreCase(client.from, 'MOBILE')) {
                        icon = ICONS.CLIENT.PHONE;
                    } else if ($F.equalsIgnoreCase(client.from, 'WECHAT')) {
                        icon = ICONS.CLIENT.WECHAT;
                    } else {
                        icon = c.customIcons[client.from] || ICONS.CLIENT.PC;
                    }
                }
            } else {
                if (icon.startWith('livebot/getIcon.do')) {
                    icon = chatServerAddr + "/" + icon;
                }
            }
            client.icon = icon;
            return icon;
        }

        function createNewTab(sessionTabId, client) {
            console.log("chat - createNewTab", "createNewTab with sessionTabId " + sessionTabId + ", client " + JSON.stringify(client));
            var sessionId = sessionTabId.substring(sessionTabId.indexOf('_') + 1),
              session = sessionsMap["session" + sessionId];
            //如果是允许自动发送翻译内容则需要初始化语言下拉列表
            setLanguageSelect('');
            var chatItem = $('<div id="' + sessionTabId + '" data="' + sessionId + '" class="chat_item">' +
              '<div class="ext">' +
              '<p class="attr"></p>' +
              '</div>' +
              '<div class="avatar">' +
              '<img class="img" src="' + client.icon + '">' +
              '</div>' +
              '<div class="info">' +
              '<h3 class="nickname">' +
              '<span class="nickname_text" title="' + client.name + '">' + client.name + '</span>' +
              '</h3>' +
              '</div>' +
              '</div>');
            chatItem.click(function () {
                $('.chat-monitor .chat_item').removeClass('active')
                $('.chat-monitor #' + sessionTabId).addClass('active')
                currentSessionId = sessionId
                searchSessionMessage(function(){}, true, sessionId)
            });
            $('.avatar img', chatItem).on('error', function () {
                var avatar = ICONS.CLIENT.PC;
                if ($F.equalsIgnoreCase(session.client.from, 'APP')) {
                    avatar = ICONS.CLIENT.PHONE;
                } else if ($F.equalsIgnoreCase(session.client.from, 'MOBILE')) {
                    avatar = ICONS.CLIENT.PHONE;
                } else if ($F.equalsIgnoreCase(session.client.from, 'WECHAT')) {
                    avatar = ICONS.CLIENT.WECHAT;
                }
                $(this).attr('src', avatar);
            });
            chatItem.appendTo($('.session_list', container));
        }

        function refreshSessionStat() {
            var closedSessionCount = $('.session_list .chat_item.closed', container).length;
            var totalSessionCount = $('.session_list .chat_item', container).length;
            if (totalSessionCount > 0) {
                $('.header .info .nickname .name_top .session_stat', container).html('(' + (totalSessionCount - closedSessionCount) + '/' + totalSessionCount + ')');
            } else {
                $('.header .info .nickname .name_top .session_stat', container).html('&nbsp;');
            }
        }

        // 状态改变的时候，检查所改变的状态是否有预约状态，如果有并且当前存在活动会话，则先改变成预约状态
        function checkForReservingStatusWhenStatusChange(status) {
            if (status === USER_STATUS.ONLINE) {
                c.currentReservedStatusId = undefined;
                return status;
            }
            if (c.userStatus[status].reservingId) {
                var totalActiveSessionCount = $('.session_list .chat_item:not(.closed)', container).length;
                if (totalActiveSessionCount > 0) {
                    c.currentReservedStatusId = status;
                    status = c.userStatus[status].reservingId;
                    $F.log('ChatMonitor - checkForReservingStatusWhenStatusChange', 'Use reserving status ' + status + ' instead of status ' + c.currentReservedStatusId);
                }
            }
            return status;
        }

        // 当会话结束时候，检查是否已经没有活动会话，并且是否有预约的状态，如果有则改变坐席装填成预约的状态
        function checkReservedStatusWhenSessionEnd() {
            if (c.currentReservedStatusId) {
                var totalActiveSessionCount = $('.session_list .chat_item:not(.closed)', container).length;
                if (totalActiveSessionCount === 0) {
                    c.changeStatus(c.currentReservedStatusId);
                    c.currentReservedStatusId = undefined;
                }
            }
        }

        /**
         * 设置会话相关按钮可用
         * @param sessionId
         */
        function enableSession(sessionId) {
            $('.btn_send', container).attr('disabled', false);
            $('.control_panel .content #edit-area', container).css({
                color: '#000'
            });
            $('.control_panel .content #edit-area', container).attr('contenteditable', true);
            $('.toolbar', container).css('display', 'flex');
            $('.chat_face', container).css('display', 'inline-block');
            $('.chat_screencut,.chat_pic', container).css('display', uploadDisabled ? 'none' : 'inline-block');
            if (c.configs.pushRatingEnabled) {
                $('.chat_push_rating', container).css('display', 'inline-block');
                let sessionCur = sessionsMap["session" + sessionId];
                if (sessionCur.hasPushedRating) {
                    $('.chat_push_rating', container).addClass('rated');
                } else {
                    $('.chat_push_rating', container).removeClass('rated');
                }
            }
            if (c.configs.translateEngine) {
                $('.chat_translate_container', container).css('display', 'inline-block');
            }
            if (showSessionButtons) {
                $('.session_hd .title_wrap .session_btn_container', container).css('display', 'inline-block');
                //会议，转接，转接队列
                $('.chat-monitor .invite, .chat-monitor .transfer, .chat-monitor .transferToQueue, ' +
                  '.session_hd .title_wrap .session_btn_container .invite, ' +
                  '.session_hd .title_wrap .session_btn_container .transfer, ' +
                  '.session_hd .title_wrap .session_btn_container .transferToQueue', container).off().click(function (e) {
                    var curSession = sessionsMap["session" + currentSessionId];
                    if (!curSession) {
                        $F.alert(i18n.error.chooseOneSessionAlert);
                        return;
                    }
                    if (!curSession.active) {
                        $F.alert(i18n.error.sessionAlreadyClosedCantTransferAlert);
                        return;
                    }
                    if (curSession.permFlag == 1) {
                        $F.alert(i18n.error.permSessionCantTransferAlert);
                        return;
                    }
                    if ($(this).hasClass('invite')) {
                        $('#tcDialog .title', container).text(i18n.sendInvite);
                        currentTIR = 'agentInvite';
                        $('#tcDialog .agentname-input-container', container).show();
                    } else if ($(this).hasClass('transfer')) {
                        $('#tcDialog .title', container).text(i18n.sendTransfer);
                        currentTIR = 'agentTransfer';
                        $('#tcDialog .agentname-input-container', container).show();
                    } else {
                        $('#tcDialog .title', container).text(i18n.sendTransferToQueue);
                        currentTIR = 'agentTransferToQueue';
                        $('#tcDialog .agentname-input-container', container).hide();
                    }

                    getAgentListByQueueId(curSession.workgroupId, curSession.queueId, function () {
                        $('#tcDialog .chat-workgroup-select', container).val(curSession.workgroupId);
                        $('#tcDialog .chat-workgroup-select', container).change();
                        $('#tcDialog .chat-queue-select', container).val(curSession.queueId);
                        $('#tcDialog', container).show().css({
                            "paddingTop": ($(container).height() - $('#tcDialog .chat-dialog-content', container).height()) / 2
                        });
                    });
                });
            }
            $('#sessionTab_' + sessionId, container).removeClass('closed');
        }

        /**
         * 设置会话相关按钮不可用
         * @param sessionId
         */
        function disableSession(sessionId) {
            if (sessionId == currentSessionId) {
                $('.btn_send', container).attr('disabled', true);
                var session = sessionsMap['session' + sessionId];
                if (session) {
                    //会话结束时候，根据客户id来缓存当时编辑的消息
                    clientCache[session.clientId] = {
                        editMessage: $('.control_panel .content #edit-area', container).html()
                    }
                    $('.control_panel .content #edit-area', container).html('')
                }
                $('.control_panel .content #edit-area', container).css({
                    color: '#b8b8b9'
                });
                $('.control_panel .content #edit-area', container).attr('contenteditable', false);
                refreshPreMessage();
                $('.toolbar', container).css("display", "none");
                $('.chat_face,.chat_screencut,.chat_pic,.chat_push_rating,.chat_translate_container', container).css('display', 'none');
                $('.session_hd .title_wrap .session_btn_container', container).css('display', 'none');
            }
            $('#sessionTab_' + sessionId, container).addClass('closed');
        }

        /**
         * 删除左侧会话标签
         * @param sessionId
         */
        function removeSessionItem(sessionId) {
            $('#sessionTab_' + sessionId, container).remove();
            delete sessionsMap["session" + sessionId];
        }

        /**
         * 设置右侧想干按钮不可用，同时删除左侧会话对应的标签
         * @param sessionId
         */
        function closeSession(sessionId) {
            disableSession(sessionId);
            removeSessionItem(sessionId);
        }

        function getDisplayMessage(message, session) {
            if (!message.displayMessage) {
                var userId = message.userId,
                  stateId = message.stateId || '',
                  userName = encodeStringByHTMLEscape(message.userName),
                  translate = message.translate || message.translateMessage ? (i18n.translationResult + message.translateMessage) : '',
                  msgText = message.text,
                  formattedTime = message.formattedTime || new Date(message.postTime).format('YYYY-MM-dd HH:mm:ss'),
                  extra = message.extra || '', extraContent = '',
                  displayMsg;
                if (extra) {
                    if (extra.Content) {
                        if (i18n.messageExtra)
                            extraContent = '<p class="js_extra_title">' + i18n.messageExtra + '</p>';
                        extraContent += '<pre class="js_extra_plain">' + extra.Content + '</pre>';
                    }
                }
                if (!msgText) {
                    $F.log('ChatMonitor - getDisplayMessage', 'Empty message: ' + JSON.stringify(message));
                    return '';
                }
                if (userId == "-1") {
                    //过滤表情字符串，把[表情]转换成表情对应的img标签
                    msgText = EMOTION.filterEmojis(msgText);
                    //把url字符串包装成a标签的连接
                    msgText = Tools.wrapURL(msgText, CHAWUR);

                    displayMsg = msgText;
                } else {
                    //解析某种格式化消息
                    msgText = Tools.parseFormattedMsg(msgText);
                    //过滤表情字符串，把[表情]转换成表情对应的img标签
                    msgText = EMOTION.filterEmojis(msgText);
                    //把url字符串包装成a标签的连接
                    msgText = Tools.wrapURL(msgText, CHAWUR);
                    // 判断消息是否需要可以翻译，根据消息是不是有文本来判断
                    let needTranslate = Tools.isNeedTranslate(msgText);

                    var avatar;
                    if (userId === c.configs.agentId) {
                        avatar = c.configs.agentHeadImg ? (headImgBaseUrl + c.configs.agentHeadImg) : ICONS.AGENT.ELITE;
                        if (translate) {
                            let messageMiddleText = EMOTION.filterEmojis(translate);
                            translate = i18n.originalText + msgText;
                            msgText = messageMiddleText;
                        }
                    } else if (userId === session.client.id) {
                        avatar = session.client.icon || setupClientIcon(session.client);
                        // if (translate)
                        //   translate = i18n.translationResult + EMOTION.filterEmojis(translate);
                    } else {
                        if (Robot.isRobot(userId)) {
                            var sessionParams = session.sessionParams;
                            var rootIcon = '';
                            if (sessionParams && sessionParams.robotEngine && sessionParams.robotEngine.icon) {
                                rootIcon = sessionParams.robotEngine.icon;
                            }
                            avatar = message.icon || rootIcon || ICONS.AGENT.ROBOT;
                        } else {
                            var user = session.agents[userId];
                            if (user) {
                                avatar = user.headImg ? (headImgBaseUrl + user.headImg) : ICONS.AGENT.OTHER_AGENT;
                            } else {
                                avatar = message.icon ? (headImgBaseUrl + message.icon) : ICONS.AGENT.OTHER_AGENT;
                            }
                        }
                    }

                    displayMsg = '<div class="clearfix" data-state="' + stateId + '">' +
                      '<div class="message ' + fetchMessageClass(userId, session) + ' '
                      + (needTranslate ? '' : 'no-translate') + ' '
                      + (translate ? 'translated' : '') + '" data-user="' + userId + '" data-session="' + session.id + '">' +
                      '<img class="avatar" src="' + avatar + '" >' +
                      '<div class="content">' +
                      '<h4 class="nickname">' + (userId !== c.configs.agentId ? userName : c.configs.agentFirstName) + ' ' + formattedTime + '</h4>' +
                      (message.revokeFlag ? '<div class="revoked">' + i18n.revoked + '<i class="reedit fas fa-info-circle" title="' + i18n.reedit + '"></i></div>' : '') +
                      (message.stateId ? '<i class="failed fa fa-exclamation-circle" style="display: none"></i>' : '') +
                      '<div class="bubble js_message_bubble ' + fetchMessageBubbleClass(userId, session) + '">' +
                      '<div class="bubble_cont' + ' ' + (message.revokable ? 'ns' : '') + '">' +
                      '<div class="plain">' +
                      '<pre class="js_message_plain" data-id="' + message.id + '">' + msgText + '</pre>' + extraContent +
                      '</div>' +
                      '</div>' +
                      (needTranslate ? ('<div class="translate-message  ' + fetchMessageBubbleClass(userId, session) + (!translate ? ' translate-hide' : '') + '">' +
                        '<div class="plain">' +
                        '<pre class="js_message_plain" data-id="' + message.id + '">' + translate + '</pre>' +
                        '</div>' +
                        '</div>') : '') +
                      '</div>' +
                      '</div>' +
                      '</div>' +
                      '</div>';
                }
                message.displayMessage = displayMsg;

                if (message.robotResponse) { // 如果消息有机器人答复，则需要拼接上相关答案
                    var displayMessageContainer = $('<div>').append(message.displayMessage);
                    $('.js_message_plain', displayMessageContainer).html(message.robotResponse);
                    message.displayMessage = displayMessageContainer.html();
                }

            }
            return message.displayMessage;
        }

        function fetchMessageClass(userId, session) {
            if (messageBubbleStyle === 'dc') { // 优先区别出客户，即所有客户的消息在左侧，其他消息都在右侧
                return userId === session.client.id ? '' : 'me';
            }
            return userId === c.configs.agentId ? 'me' : ''; // 优先区别出当前坐席，即所有当前坐席的消息在左侧，其他消息都在右侧（默认）
        }

        function fetchMessageBubbleClass(userId, session) {
            if (messageBubbleStyle === 'dc') { // 优先区别出客户，即所有客户的消息在左侧，其他消息都在右侧
                return userId === session.client.id ? 'bubble_default left' : 'bubble_primary right';
            }
            return userId === c.configs.agentId ? 'bubble_primary right' : 'bubble_default left'
        }

        function formatFeedbackMessage(msg) {
            return '<p class="message_system">' + msg + '</p>';
        }

        function appendTextToDiv(content, containerId = 'agentResponseDiv') {
            var target;
            try {
                target = $(content);
            } catch (e) {
            }
            if (!target || target.length === 0) {
                target = $('<div>' + content + '</div>');
            }

            // 包装消息，绑定各种消息事件
            wrapMessage(target, containerId);

            $('#' + containerId, container).append(target);
            scrollToBottom('.message_panel');
        }

        /**
         * 包装消息，绑定各种消息事件
         * @param containerId agentResponseDiv
         * @param target 消息的dom对象
         */
        function wrapMessage(target, containerId = 'agentResponseDiv') {
            //给图片添加点击事件 放大图片显示
            $('img:not(.avatar,.qqemoji,.standard-emoji,.location,.custom-emoji,div.message-imgtext .thumb,div.message-card .card-img)', target).one('load', function () {
                $(this).css("cursor", "pointer").on("click", function () {
                    Tools.showOriginImage(this, chatServerAddr, $('img:not(.avatar,.qqemoji,.standard-emoji,.location,.custom-emoji)', $('#' + containerId)));
                });
                Tools.autoResizeImage(300, 300, this);
                scrollToBottom('.message_panel');
            });
            //给voice添加点击事件，播放语音
            $('div.message-voice', target).off().on('click', function () {
                var $voice = $(this);
                $('div.message-voice').removeClass('active');
                var url = $voice.attr('data-url');
                if (url) {
                    if (currentVoiceAudio && !currentVoiceAudio.paused && !currentVoiceAudio.ended && 0 < currentVoiceAudio.currentTime) {
                        currentVoiceAudio.pause();
                        currentVoiceAudio.currentTime = 0;
                        $voice.removeClass('active');
                        return;
                    }
                    if (!$voice.hasClass('listened')) {
                        $voice.addClass('listened');
                    }
                    if (!url.toLowerCase().startsWith("http")) {
                        url = chatServerHost + url;
                    }
                    currentVoiceAudio = new Audio(url);
                    $(currentVoiceAudio).on('play', function () {
                        $voice.addClass('active');
                    }).on('ended', function () {
                        $voice.removeClass('active');
                    }).on('error', function () {
                        $voice.removeClass('active');
                    });
                    currentVoiceAudio.play();
                }
            });
            $('div.message-file', target).off().on('click', function () {
                var $file = $(this);
                var url = $file.attr('data-url');
                if (url) {
                    if (!url.toLowerCase().startsWith("http")) {
                        url = chatServerHost + url;
                    }
                    window.open(url, 'FILE_DOWNLOAD');
                }
            });
            $('div.message-location', target).off().on('click', function () {
                var $location = $(this);
                var latitude = $location.attr('data-latitude'),
                  longitude = $location.attr('data-longitude'),
                  label = $location.attr('data-address'),
                  map = $location.attr('data-map'),
                  mapUrl = 'aMaps.html';
                if (map === 'baidu') {
                    mapUrl = 'baiduMaps.html'
                } else if (map === 'tencent') {
                    mapUrl = 'tencentMaps.html'
                }
                window.open(chatServerAddr + '/' + mapUrl + '?latitude=' + latitude + '&longitude=' + longitude + '&label=' + encodeURIComponent(label), '_blank');
            });
            $('div.message-imgtext, div.message-card', target).off().on('click', function () {
                var url = $(this).attr('data-url');
                var agentMute = $(this).attr('data-agent-mute');
                if (url && !agentMute)
                    window.open(url, '_blank');
            });
            $('video', target).each(function (i, video) {
                var $video = $(video), src = $video.attr('src') || $('source', $video).attr('src');
                if (src) {
                    if (!src.toLowerCase().startsWith('http')) {
                        src = chatServerHost + src;
                    }
                    $video.attr('src') ? $video.attr('src', src) : $('source', $video).attr('src', src);
                    $video.css('width', 300).on('canplay', function () {
                        scrollToBottom('.message_panel');
                    });
                    //退出全屏会自动滚到最顶部，没法记住原来滚动到的位置，目前只能退出全屏时候滚到最下面
                    $video.on('webkitfullscreenchange', function () {
                        var isFullscreenNow = document.webkitFullscreenElement !== null;
                        if (isFullscreenNow) {

                        } else {
                            scrollToBottom('.message_panel');
                        }
                    });
                }
            });

            $('.message', target).each(function (i, msg) {
                var userId = $(this).attr('data-user'),
                  sessionId = $(this).attr('data-session');
                $('.avatar', this).off().on('error', function () {
                    var avatar, session = sessionsMap["session" + sessionId];
                    if (userId === c.configs.agentId) {
                        avatar = ICONS.AGENT.ELITE
                    } else if (userId === session.client.id) {
                        if ($F.equalsIgnoreCase(session.client.from, 'APP')) {
                            avatar = ICONS.CLIENT.PHONE;
                        } else if ($F.equalsIgnoreCase(session.client.from, 'MOBILE')) {
                            avatar = ICONS.CLIENT.PHONE;
                        } else if ($F.equalsIgnoreCase(session.client.from, 'WECHAT')) {
                            avatar = ICONS.CLIENT.WECHAT;
                        } else {
                            avatar = ICONS.CLIENT.PC;
                        }
                    } else {
                        avatar = ICONS.AGENT.OTHER_AGENT;
                    }
                    $(this).attr('src', avatar);
                });
            });

            if (messageRevokeEnabled) {
                $.contextMenu({
                    selector: '.chat-monitor .message.me .bubble_cont.ns',
                    callback: function (key, options, target) {
                        if (key === 'revoke') {
                            var messageId = $('.js_message_plain', target).attr('data-id');
                            var sessionId = $(target).parent().parent().parent().attr('data-session');
                            callService({
                                data: {
                                    requestType: 'send',
                                    data: getPostNoticeMessageSentInfo(messageId, sessionId, NOTICE_TYPE.REVOKE_MESSAGE)
                                }
                            }).done(function (data) {
                                if (data.status === 'success' && data.sendResponse && data.sendResponse.result == 1) {
                                    $F.notify(i18n.revokedSuccess);
                                    //删除这条消息
                                    target.removeClass('ns');
                                    $('<div class="revoked">' + i18n.revoked + '<i class="reedit fas fa-info-circle" title="' + i18n.reedit + '"></i></div>').insertBefore(target.parent());
                                    $('.reedit', target.parent().parent()).on('click', function () {
                                        reedit($(this).parent().parent(), container);
                                    });
                                    const sessionCur = sessionsMap["session" + sessionId];
                                    if (sessionCur && sessionCur.allMessages) {
                                        sessionCur.allMessages.forEach(function (message) {
                                            if (message.id == messageId) {
                                                message.revokeFlag = 1;
                                                message.revokable = false;
                                                // 清空这条消息显示缓存
                                                message.displayMessage = undefined;
                                            }
                                            if (message.userId.length === 36) {
                                                setUserInWaiting(sessionCur, true);
                                            } else {
                                                if (message.type === MESSAGE_TYPE.NORMAL && message.revokeFlag !== 1) {
                                                    setUserInWaiting(sessionCur, false);
                                                }
                                            }
                                        });
                                    }
                                } else {
                                    $F.alert(i18n.error.revokeMessageFailed + (data.sendResponse.result === -37 ? ': 消息超时' : ''));
                                }
                            }).fail(function () {
                                $F.err('ChatMonitor - messageRevoke', i18n.error.revokeMessageFailed);
                            });
                        }
                    },
                    iconStyle: 'fa',
                    items: {'revoke': {name: i18n.revoke, icon: "undo"}},
                    appendTo: container
                });
            }

            if (c.configs && c.configs.translateEngine) {
                $.contextMenu({
                    selector: '.chat-monitor .message:not(.me,.translated,.no-translate) .plain',
                    callback: function (key, options, target) {
                        if (key === 'translate') {
                            if ($(target).hasClass('translated'))
                                return;
                            var content = $('.js_message_plain', target).html(),
                              messageId = $('.js_message_plain', target).data("id");
                            callService({
                                data: {
                                    requestType: 'translate',
                                    text: content,
                                    messageId: messageId,
                                    targetLang: $.cookie('chat.translateTo') || 'zh'
                                }
                            }).done(function (data) {
                                if (data.status === "success") {
                                    $(target).addClass('translated');
                                    $('.bubble_cont', target)
                                      .after('<div class="translate-message">' +
                                        '<div class="plain">' +
                                        '<pre class="js_message_plain" data-id="">' + i18n.translationResult + data.text + '</pre>' +
                                        '</div>' +
                                        '</div>');
                                } else {
                                    $F.err('ChatMonitor - translate', i18n.error.translateFailed + ': ' + data.message);
                                }
                            }).fail(function (e) {
                                $F.err('ChatMonitor - translate', i18n.error.translateFailed);
                            });
                        }
                    },
                    iconStyle: 'fa',
                    items: {'translate': {name: i18n.translate, icon: "language"}},
                    appendTo: container
                });
            }

            $('.message .js_message_plain', target).off().on('click', function () {
                var content = $(this).html();
                notifyProjectEvent($CONST.ChatEvent.CHAT_MESSAGE_CLICKED || 'CHAT_MESSAGE_CLICKED', {
                    sessionId: currentSessionId,
                    message: content,
                    customerGuid: currentCustomerGuid
                });
            });

            //坐席辅助信息点击处理
            Robot.wrapResponse($('.robotResponseWrapper', target), function (answer) {
                let curSession = sessionsMap["session" + currentSessionId];
                if (curSession && curSession.active) {
                    $('.control_panel .content #edit-area', container).html(answer);
                }
            });

            // 撤回后，重新编辑按钮
            $('.reedit', target).off().on('click', function () {
                reedit($(this).parent().parent(), container);
            });
        }

        function scrollToBottom(selector) {
            var target = $(selector, container)[0];
            if (target) {
                target.scrollTop = target.scrollHeight;
            }
        }

        function reedit(messageContainer, container) {
            let curSession = sessionsMap["session" + currentSessionId];
            if (curSession && curSession.active) {
                let content;
                const translateMessageDom = $('.translate-message .js_message_plain', messageContainer);
                if (translateMessageDom.length > 0 && translateMessageDom.html()) {
                    content = translateMessageDom.html().substring(3); // 去掉 “原文：”
                } else {
                    content = $('.js_message_plain', messageContainer).html();
                }
                $('.control_panel .content #edit-area', container).append(content);
            }
        }

        /**
         * 封装要发送出去的消息的json数据
         * @param message 消息正文
         * @param sessionId 会话id
         * @param messageType 消息类型，默认就是普通消息， 2表示系统自动发送的消息
         * @param extra 消息的附加信息
         */
        function getPostMessageSentInfoJSONWithSessionId(message, sessionId, messageType, extra, senderPid) {
            var sentInfo = {
                senderId: c.configs.agentId,
                actionType: 'postMessage',
                sessionId: sessionId,
                message: message,
                postTime: new Date($F.getDbTime()).getTime()
            };
            if (messageType) {
                sentInfo.messageType = messageType;
            }
            if (extra) {
                sentInfo.extra = JSON.stringify(extra);
            }
            if (senderPid) {
                sentInfo.senderPid = senderPid;
            }
            var sentInfoStr = JSON.stringify(sentInfo);
            $F.log('ChatMonitor - getPostMessageSentInfoJSONWithSessionId', sentInfoStr);
            return sentInfoStr;
        }

        function getPostNoticeMessageSentInfo(message, sessionId, noticeType, receiverId) {
            var sentInfo = {
                senderId: c.configs.agentId,
                actionType: "postNoticeMessage",
                sessionId: sessionId,
                noticeType: noticeType,
                message: message,
                receiverId: receiverId
            };
            return JSON.stringify(sentInfo);
        }

        /**
         * 发送消息
         * @param content 用来发送出去的消息内容
         * @param sessionId 会话id
         * @param [contentToDisplay] 用来当前显示到自己的界面的消息内容
         * @param [extra] 消息附加信息
         * @param [success] 成功回调
         * @param [fail] 失败回调
         */
        function sendMessage(content, sessionId, contentToDisplay, extra, success, fail) {
            if (!sessionsMap['session' + currentSessionId].active) {
                return
            }
            sessionId = sessionId || currentSessionId;
            content = tools.parseContent(content);
            contentToDisplay = contentToDisplay || content;
            contentToDisplay = tools.parseDisplayContent(contentToDisplay);
            // contentToDisplay = Tools.cottrollerFILE(contentToDisplay);

            // TODO: 调用接口之前，先显示要发送的消息
            let clientMessageId = '_message-' + new Date().getTime()
              , session = sessionsMap["session" + sessionId]
              , message = addMessageToSession(sessionId, {
                id: c.configs.agentId,
                name: c.staff.displayName
            }, {stateId: clientMessageId, text: contentToDisplay, translate: false}, new Date().format('YYYY-MM-dd HH:mm:ss'));
            message.revokable = true;
            appendTextToDiv(getDisplayMessage(message, session));
            var $domMessage = '.chat-monitor .clearfix[data-state=' + clientMessageId + ']';
            const senderPId = $('#send_by').val() === 'original' ? currentStaffId : undefined;
            callService({
                data: {
                    requestType: "send",
                    data: getPostMessageSentInfoJSONWithSessionId(content, sessionId, 0, extra, senderPId)
                }
            }).done(function (data) {
                if (data.status === 'success') {
                    if (-39 === data.sendResponse.result) {
                        if ($.isFunction(fail)) {
                            fail(data, $domMessage);
                        }
                    } else {
                        var messageId = data.sendResponse ? data.sendResponse.newMessageId : ('i' + _messageId++);
                        let translateMessage = data.sendResponse ? data.sendResponse.translateMessage : '';
                        var session = sessionsMap["session" + sessionId];
                        session.preMsgUserId = c.configs.agentId;
                        setUserInWaiting(session, false);
                        session.lastAgentMessageSentTime = new Date().getTime();
                        if (!session.firstReply) {
                            session.firstReply = true;
                            // 坐席第一次回复消息时候触发此消息
                            notifyProjectEvent($CONST.ChatEvent.CHAT_SESSION_FIRST_REPLY || 'CHAT_SESSION_FIRST_REPLY', {
                                sessionId: sessionId
                            });
                        }
                        //通知坐席发送消息
                        notifyProjectEvent($CONST.ChatEvent.AGENT_SEND_MESSAGE || 'AGENT_SEND_MESSAGE', {
                            sessionId: sessionId,
                            message: message
                        });
                        // $('.chat-monitor .clearfix[data-state=' + clientMessageId + ']').remove();
                        $(".js_message_plain", $domMessage).attr('data-id', messageId)
                        if (translateMessage && !$('.no-translate', $domMessage)[0]) {
                            let sessionCur = sessionsMap["session" + sessionId];
                            sessionCur.allMessages.forEach(function (message) {
                                if (message.stateId === clientMessageId) {
                                    message.translate = translateMessage;
                                    message.displayMessage = '';
                                    getDisplayMessage(message, sessionCur);
                                }

                            })
                            $('.translate-message', $domMessage).removeClass("translate-hide");
                            $(".js_message_plain", $('.translate-message', $domMessage)).html(i18n.originalText + contentToDisplay);
                            $(".js_message_plain", $('.bubble_cont', $domMessage)).html(i18n.translationResult + EMOTION.filterEmojis(translateMessage));
                            Tools.addImageClick($domMessage, chatServerAddr, function () {
                                scrollToBottom('.message_panel');
                            })
                        }
                    }
                    if ($.isFunction(success)) {
                        success(data);
                    }
                } else {
                    $F.err('ChatMonitor - sendMessage', i18n.error.sendMessageFailed);
                    if ($.isFunction(fail)) {
                        fail(data, $domMessage);
                    }
                }
            }).fail(function () {
                $F.err('ChatMonitor - sendMessage', i18n.error.sendMessageFailed);
                if ($.isFunction(fail)) {
                    fail(null, $domMessage);
                }
            });
            if (!chatMonitorPull) {
                setTimeout(() => {
                    searchSessionMessage(null, true, currentSessionId)
                }, 2000)
            }
        }

        function encodeStringByHTMLEscape(str) {
            if (!str)
                return str;
            else {
                //handle encoding key html characters
                str = str.replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/\\/g, '&#92').replace(/\//g, '&#47');
                str = str.replace(/\r\n/g, '<br/>').replace(/\n\r/g, '<br/>').replace(/\r/g, '<br/>').replace(/\n/g, '<br/>').replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;').replace(/\b/g, '');
                return str;
            }
        }

        /**
         * 结束指定聊天会话，但不关闭
         */
        function endSession(sessionId, callNatures, comments) {
            if (sessionId) {
                disableSession(sessionId);
                sinkSession(sessionId);
                var session = sessionsMap["session" + sessionId];
                var sentInfoJson = JSON.stringify({
                    actionType: "closeSession",
                    senderId: c.configs.agentId,
                    senderName: c.staff.displayName,
                    sessionId: sessionId,
                    callNatures: typeof (callNatures) === 'string' ? callNatures : JSON.stringify(callNatures),
                    comments: comments
                });
                callService({
                    data: {
                        requestType: "send",
                        data: sentInfoJson
                    }
                }, true);
                if (session) {
                    session.active = false;
                    session.endTime = new Date().getTime();
                }
                refreshSessionStat();
                checkReservedStatusWhenSessionEnd();
            }
        }

        function topSession(sessionId) {
            if ($('#sessionTab_' + sessionId, container).hasClass('top')) {
                $('.session_list .chat_item.top', container).first().before($('#sessionTab_' + sessionId, container));
            } else {
                $('.session_list .chat_item:not(.top)', container).first().before($('#sessionTab_' + sessionId, container));
            }
        }

        function sinkSession(sessionId) {
            if (sinkAfterEnds) {
                var allSessionItems;
                if ($('#sessionTab_' + sessionId, container).hasClass('top')) {
                    allSessionItems = $('.session_list .chat_item.top', container);
                } else {
                    allSessionItems = $('.session_list .chat_item', container);
                }
                //移动session到关闭了的会话的顶部
                $.each(allSessionItems, function (i, sessionItem) {
                    var sId = $(sessionItem).attr('data');
                    if (sId != sessionId) {
                        var s = sessionsMap["session" + sId];
                        if (s && !s.active) {
                            $(sessionItem).before($('#sessionTab_' + sessionId, container));
                            return false;
                        } else {
                            if (i === allSessionItems.length - 1) {
                                $(sessionItem).after($('#sessionTab_' + sessionId, container));
                            }
                        }
                    }
                });
            }
        }

        function createSession(sessionId, client, queueId, queueName, sessionParams, eventGuid) {
            var newSession = new Session(sessionId);
            newSession.clientId = client.id;
            newSession.client = client;
            newSession.lang = client.lang;
            newSession.queueId = queueId;
            var workgroup = c.findWorkgroupByQueueId(queueId);
            if (workgroup) {
                newSession.workgroupId = workgroup.id;
                newSession.workgroupName = workgroup.name;
            }
            newSession.queueName = queueName;
            newSession.eventGuid = eventGuid || '';
            $F.log("ChatMonitor - createSession", sessionId + " clientId " + client.id);
            if (sessionParams) {
                if (typeof (sessionParams) === 'string') {
                    sessionParams = JSON.parse(sessionParams);
                }
                newSession.serviceAccountId = sessionParams.serviceAccountId;
                newSession.serviceAccountName = sessionParams.serviceAccountName;
                var browserName = '';
                var os = '';
                if (sessionParams.metaData) {
                    browserName = sessionParams.metaData.name;
                    os = sessionParams.metaData.os;
                }
                newSession.sessionParams = {
                    id: sessionId,
                    ip: sessionParams.ip,
                    browser: browserName,
                    os: os,
                    creationTime: newSession.creationTime,
                    queueId: queueId,
                    queueName: queueName,
                    robotEngine: sessionParams.robotEngine
                };
                $F.log("ChatMonitor - createSession", "session params", newSession.sessionParams);
            }
            //set default allow client send attachment
            newSession.allowClientAttach = c.configs.allowClientSendAttachment;
            if (newSession.allowClientAttach) {
                callService({
                    data: {
                        requestType: "sessionSetting",
                        sessionId: sessionId,
                        settingType: "allowClientAttach",
                        value: 1
                    }
                }, true);
            }

            if (clientCache[client.id]) {
                newSession.editingMessage = clientCache[client.id].editMessage || ''
            }
            return newSession;
        }

        /**
         * 根据队列号找到工作组id
         * @param queueId
         * @returns {*}
         */
        this.findWorkgroupByQueueId = function (queueId) {
            var result;
            this.workgroups.some(function (w) {
                var find = w.queues.some(function (q) {
                    return q.id === queueId;
                });
                if (find) {
                    result = w;
                    return true;
                }
            });
            return result;
        };

        /**
         * 暴露出方法给动态页面调用
         * 获取非离线坐席列表
         * @param queueId 队列号
         * @param sessionId 会话id
         * @param workgroupId 工作組id
         */
        this.getNonOfflineAgentList = function (queueId, sessionId, workgroupId) {
            return callService({
                data: {
                    requestType: 'getNonOfflineAgentList',
                    queueId: queueId,
                    sessionId: sessionId,
                    workgroupId: workgroupId
                }
            })
        };
        /**
         * 修改坐席状态
         * @param status 状态id
         * @param retry 是否失败重试
         * @param mute 是否异常时候弹出报错
         */
        this.changeStatus = function (status, retry, mute) {
            var c = this;
            var busyId = $F.busyShow();
            return new Promise(resolve => {
                callService({
                    data: {
                        requestType: "changeStatus",
                        status: status
                    }
                }, retry).done(data => {
                    $F.busyHide(busyId);
                    if (data && data.status === "success") {
                        c.currentUserStatus = status;
                        c.setUserStatus();
                        c.hideUserStatusMenu();
                        resolve(1);
                    } else {
                        if (!mute) {
                            let failMessage = data.message ? data.message : i18n.error.switchStatusFailed;
                            $F.alert(failMessage);
                        }
                        resolve(-1);
                    }
                }).fail(jqXHR => {
                    $F.busyHide(busyId);
                    if (!mute) {
                        $F.alert(i18n.error.switchStatusFailed + ": " + jqXHR.status + ' ' + jqXHR.statusText);
                    }
                    resolve(-1);
                });
            })
        };

        this.changeToExceptionStatus = function () {
            callService({
                data: {
                    requestType: "changeToExceptionStatus"
                }
            });
        };

        /**
         * 添加自定义的工具条按钮，支持传入对象或者数组
         * btn支持属性：
         *    label 标签
         *    tooltip 鼠标放上去后提示
         *    click 点击后回调
         *    style 样式
         * @param btns
         */
        this.addCustomToolbarBtns = function (btns) {
            if (btns) {
                if (!$.isArray(btns)) {
                    btns = [btns];
                }
                btns.forEach(btn => {
                    $('<a style="' + (btn.style || '') + '" class="chat_custom_btn" href="javascript:;" title="' + (btn.tooltip || btn.label) + '">' + btn.label + '</a>').on('click', () => {
                        if ($.isFunction(btn.click)) {
                            btn.click({
                                sessionId: currentSessionId,
                                customerGuid: currentCustomerGuid
                            });
                        }
                    }).appendTo($('.toolbar', container));
                })
            }
        };

        /**
         * 更新qq和emoji表情的显隐，提供给动态页面调用，动态页面可以根据当前会话类型自行决定显示qq还是emoji
         * @param options {object} {qq:true, emoji: false}
         */
        this.setEmojiState = function (options) {
            if (options) {
                if (options.qq === true) {
                    $('.chat-monitor .exp_hd .qq', container).removeAttr("style");
                    $('.chat-monitor .exp_bd .qq', container).removeAttr("style");
                    $('.chat-monitor .exp_hd .qq', container).addClass('active');
                    $('.chat-monitor .exp_bd .qq', container).addClass('active');
                } else if (options.qq === false) {
                    $('.chat-monitor .exp_hd .qq', container).hide();
                    $('.chat-monitor .exp_bd .qq', container).hide();
                }
                if (options.emoji === true) {
                    $('.chat-monitor .exp_hd .emoji', container).removeAttr("style");
                    $('.chat-monitor .exp_bd .emoji', container).removeAttr("style");
                    $('.chat-monitor .exp_hd .emoji', container).addClass('active');
                    $('.chat-monitor .exp_bd .emoji', container).addClass('active');
                } else if (options.emoji === false) {
                    $('.chat-monitor .exp_hd .emoji', container).hide();
                    $('.chat-monitor .exp_bd .emoji', container).hide();
                }
            }
        };

        /**
         * 设置某个会话中的允许发送的附件类型
         * @param sessionId 会话id
         * @param acceptExtensions 允许发送的附件文件后缀数组 ['jpg','png','gif','jpeg']
         */
        this.setSessionFileAcceptExtensions = function (sessionId, acceptExtensions) {
            var session = sessionsMap["session" + sessionId];
            if (session && acceptExtensions) {
                session.fileAcceptExtensions = acceptExtensions;
            }
        };

        /**
         * 根据sessionId或者session对象
         * @param sessionId
         */
        this.getSession = function (sessionId) {
            var session = sessionsMap["session" + sessionId];
            return session;
        };

        function getAgentListByQueueId(workgroupId, queueId, callback) {
            var contacts = $('#tcDialog .contacts', container);
            if (currentTIR === 'agentTransferToQueue') {
                contacts.html("");
                callback && callback();
                return;
            }
            c.getNonOfflineAgentList(queueId, currentSessionId, workgroupId).done(function (data) {
                if (data.status === "success") {
                    c.agentList = data.agentList;
                    var filterName = $('#tcDialog .agentname-input', container).val();
                    if (filterName) {
                        var filteredAgentList = c.agentList.filter(function (agent) {
                            var agentName = agent.name || agent.firstName;
                            return agentName.indexOf(filterName) > -1;
                        });
                        setupAgentsForTC(contacts, filteredAgentList, filterName);
                    } else {
                        setupAgentsForTC(contacts, c.agentList);
                    }
                }
            }).fail(function () {
                $F.err('ChatMonitor - getAgentListByQueueId', i18n.error.getAgentListFailed);
            }).always(function () {
                callback && callback();
            });
        }


        function setupAgentsForTC(contactsContainer, agentList, filterName) {
            contactsContainer.html("");
            if (agentList.length === 0) {
                contactsContainer.append('<span class="contact_notice">' + i18n.noAgents + '</span>');
            } else {
                contactsContainer.append('<div class="online"><h4 class="contact_title">' + i18n.online + '</h4></div>');
                contactsContainer.append('<div class="notOffline"><h4 class="contact_title">' + i18n.nonOffline + '</h4></div>');
                $.each(agentList, function (i, agent) {
                    let agentName = agent.name || agent.firstName;//为了兼容老版本chat，老的里没返回agent.name
                    if (agent.lastName) {
                        agentName = agentName + " - " + agent.lastName;
                    }
                    if (filterName) {
                        agentName = agentName.replace(filterName, '<span style="background: #f1c40f">' + filterName + '</span>');
                    }
                    agentName = agentName + ' (' + agent.activeSessionCount + ')';
                    $(agent.statusId == 1 ? '.online' : '.notOffline', contactsContainer).append(
                      '<div class="contact_item" data-id="' + agent.id + '">' +
                      '<div class="opt">' +
                      '<i class="web_wechat_choose_wireframe"></i>' +
                      '</div>' +
                      '<div class="info">' +
                      '<h4 class="nickname">' + agentName + '</h4>' +
                      '</div>' +
                      '</div>');
                });
            }

            $('.contact_item', contactsContainer).click(function () {
                $('.contact_item', contactsContainer).removeClass('active');
                $('.contact_item i', contactsContainer).removeClass('web_wechat_choose_green');
                $(this).addClass('active');
                $('i', $(this)).toggleClass('web_wechat_choose_green');
            });
        }


        //刷新预览信息
        function refreshPreMessage(msg, sessionId) {
            if (!msg) {
                $(".pre_message_container", container).html("").hide();
            } else {
                if (c.configs.realtimeCheck) {
                    $(".pre_message_container", container).text($('<div>').html(msg).text()).show();
                }
            }
            if (sessionId)
                sessionsMap["session" + sessionId].previewMessage = msg || '';
        }

        /**
         * 发送系统自动消息
         * @param session 发送的会话
         * @param messageText 消息内容
         * @param messageType 消息类型（自动发送消息的类型）
         * @param successHandler 成功发送回调
         */
        function sendSystemAutoMessage(session, messageText, messageType, successHandler) {
            if (messageText) {
                var sessionId = session.id;
                callService({
                    data: {
                        requestType: 'send',
                        data: getPostMessageSentInfoJSONWithSessionId(messageText, sessionId, messageType)
                    },
                    success: data => {
                        if (data.status === 'success') {
                            let traslateMessage = data.sendResponse ? data.sendResponse.translateMessage : '';
                            var message = addMessageToSession(sessionId, {
                                  id: c.configs.agentId,
                                  name: c.staff.displayName
                              }, {text: messageText, translate: traslateMessage, type: messageType, systemNotice: true}
                              , new Date().format('YYYY-MM-dd HH:mm:ss'));
                            if (currentSessionId == sessionId) {
                                var displayMessage = getDisplayMessage(message, session);
                                appendTextToDiv(displayMessage);
                                showMessageOnItem(sessionId, message.text);
                            }
                        }
                        if ($.isFunction(successHandler)) {
                            successHandler(data);
                        }
                    }
                }, true);
            }
        }

        function userWaitingElapseTicker(c) {
            try {
                var now = new Date();
                $.each(sessionsMap, function (key, session) {
                    if (session && session.active && session.permFlag != 1) {
                        if (session.userInWaiting) {
                            var lastAutoReplyElapsed = Math.floor((now.getTime() - session.lastAutoReplyMessageTime) / 1000);
                            if (c.configs.timeoutForClientWait > 0 && lastAutoReplyElapsed >= c.configs.timeoutForClientWait
                              && (sysAutoReplyMessageTimes == 0 || (sysAutoReplyMessageTimes > 0 && sysAutoReplyMessageTimes > session.autoReplyMessageTimes))) {
                                session.autoReplyMessageTimes++;
                                session.lastAutoReplyMessageTime = now.getTime();
                                $F.log('ChatMonitor - userWaitingElapseTicker', 'send autoReplyMessageForClientWaitTimeout for lastAutoReplyElapsed ' + lastAutoReplyElapsed);
                                getPropertyByQueue('autoReplyMessageForClientWaitTimeout', session.queueId, session.lang).then(autoReplayMessage => {
                                    let message = autoReplayMessage, arms = autoReplayMessage.split('###'); // 可以用###来分隔多条消息，每次发送随机一条消息
                                    if (arms.length > 0) {
                                        message = arms[Math.floor(Math.random() * arms.length)];
                                    }
                                    sendSystemAutoMessage(session, message, MESSAGE_TYPE.USER_IN_WAITING_MESSAGE);
                                });
                            }
                        } else {
                            // 锁定的会话不会触发afk自动关闭逻辑
                            if (!session.locked) {
                                //handle auto close session by long time no response from client side
                                var afkElapsed = session.lastAgentMessageSentTime;
                                if (afkElapsed == -1) {
                                    afkElapsed = session.creationTime;
                                }
                                afkElapsed = now.getTime() - afkElapsed;
                                var nmd = c.configs.userAFKElapsedNotifyMessageDuration * 1000;
                                if (nmd > 0) {
                                    if (afkElapsed > nmd && !session.hasUserNoResponseNotified) {
                                        //send notification
                                        $F.log('ChatMonitor - userWaitingElapseTicker', "session " + session.id + " send user AFK notification.");
                                        session.hasUserNoResponseNotified = true;
                                        session.lastAgentMessageSentTime = now.getTime();
                                        afkElapsed = 0;
                                        getPropertyByQueue('userAFKElapsedNotifyMessage', session.queueId, session.lang).then(userAFKElapsedNotifyMessage => {
                                            sendSystemAutoMessage(session, userAFKElapsedNotifyMessage, MESSAGE_TYPE.USER_AFK_NOTIFY_MESSAGE);
                                        });
                                    }
                                }
                                var csd = c.configs.userAFKElapsedCloseSessionDuration * 1000;
                                if (csd > 0) {
                                    if (afkElapsed > csd && session.hasUserNoResponseNotified && !session.hasCloseAFK) {
                                        //close session
                                        $F.log('ChatMonitor - userWaitingElapseTicker', "session " + session.id + " send user AFK close session message.");
                                        getPropertyByQueue('userAFKElapsedCloseSessionMessage', session.queueId, session.lang, '客户AFK，自动结束').then(messageText => {
                                            var sessionId = session.id;
                                            var message = addMessageToSession(sessionId, {
                                                id: c.configs.agentId,
                                                name: c.staff.displayName
                                            }, {text: messageText, type: MESSAGE_TYPE.USER_AFK_CLOSE_SESSION_MESSAGE});
                                            if (currentSessionId == sessionId) {
                                                var displayMessage = getDisplayMessage(message, session);
                                                appendTextToDiv(displayMessage);
                                            }
                                            $F.log('ChatMonitor - userWaitingElapseTicker', "Close session " + session.id + " due to user AFK");
                                            const senderPId = $('#send_by').val() === 'original' ? currentStaffId : undefined;
                                            callService({
                                                data: {
                                                    requestType: 'agentCloseAFKClient',
                                                    sessionId: sessionId,
                                                    agentId: c.configs.agentId,
                                                    data: getPostMessageSentInfoJSONWithSessionId(message.text, sessionId, MESSAGE_TYPE.USER_AFK_CLOSE_SESSION_MESSAGE, undefined, senderPId)
                                                }
                                            }, true).always(function () {
                                                disableSession(sessionId);
                                            });
                                            session.hasCloseAFK = true;
                                            session.lastAgentMessageSentTime = now.getTime();
                                        });
                                    }
                                }
                            }
                        }

                        if (session.userInWaiting) {
                            //1. 左侧item时间，显示几分钟前，大于1小时，就显示1小时前
                            var chatItem = $('#sessionTab_' + session.id, container);
                            if (chatItem.length > 0) {
                                var timediff = new Date().getTime() - session.lastUserMessageReceivedTime;
                                if (timediff > 60 * 60 * 1000) {
                                    $('.ext .attr', chatItem).html(i18n.oneHourAgo);
                                } else if (timediff > 60 * 1000) {
                                    $('.ext .attr', chatItem).html((Math.floor(timediff / 60 / 1000)) + i18n.minutesAgo);
                                }
                                //2. 这个时间超时多长时间变红
                                if (!isNaN(lastChattingTimeThreshold) && lastChattingTimeThreshold > 0) {
                                    if (timediff > lastChattingTimeThreshold * 1000) {
                                        $('.ext .attr', chatItem).html('<span style="color: red">' + $('.ext .attr', chatItem).html() + '</span>');
                                    }
                                }
                            }
                        }
                    }
                });

                //3. 聊天总时长显示在聊天右侧顶部
                var sessionCur = sessionsMap["session" + currentSessionId];
                if (sessionCur) {
                    var lastingTime;
                    if (sessionCur.active) {
                        lastingTime = new Date().getTime() - sessionCur.creationTime;
                        $('.session_hd .session_last', container).html(i18n.lasting + ':' + Tools.getFormattedLasting(lastingTime));
                    }
                }

            } catch (e) {
                $F.err('ChatMonitor', "Error occurred on userWaitingElapseTicker : " + e.message);
            }
            userWaitingTimer = setTimeout(function () {
                userWaitingElapseTicker(c);
            }, 1000);
        }

        function uploadDataURL(content, fileName, uploadUrl) {
            var busyId = $F.busyShow(i18n.dyn.loading + ': ' + i18n.imageUploading);
            var postData = {
                filename: fileName,
                dataURI: content
            };
            $F.log('ChatMonitor - uploadDataURL', 'Upload file: ' + fileName + ', size:' + content.length + ', upload:' + uploadUrl);
            // 上传的数据除了图片外，还可以包含自己需要传递的参数
            var csId = currentSessionId;
            $.ajax({
                type: 'POST',
                url: uploadUrl,
                dataType: "json",
                data: postData,
                cache: false,
                xhrFields: {
                    withCredentials: true
                }
            }).done(function (data) {
                if (data) {
                    if (data.url) {
                        var displayUrl = chatServerHost + data.url,
                          content = '<img data-from="elite" src = "' + data.url + '" >',
                          displayContent = '<img data-from="elite" src = "' + displayUrl + '" style="max-width: 300px;max-height: 300px;vertical-align: baseline" data-url="' + data.url + '">';
                        $F.log('ChatMonitor - uploadDataURL', 'UploadDataURL Done, download path:' + displayUrl);
                        if (editImageAfterPaste) {
                            Tools.appendToEditDiv(displayContent);
                        } else {
                            Tools.confirm(i18n.sendCaptureConfirm + '<div>' + displayContent + '</div>', function () {
                                sendMessage(content, csId, displayContent);
                            });
                        }
                    } else {
                        $F.log('ChatMonitor - uploadDataURL', 'UploadDataURL Done, download failed:' + data.msg);
                        $F.alert(i18n.error.uploadFailed + ': ' + (data.msg || i18n.error.serverError));
                    }
                }
            }).fail(function (jqXHR) {
                $F.err('ChatMonitor - uploadDataURL', 'UploadDataURL failed: ' + jqXHR.status + ' ' + jqXHR.statusText);
                $F.alert(i18n.error.uploadFailed + ': ' + i18n.error.serverError);
            }).always(function () {
                $F.busyHide(busyId);
            });
        }


        function updateClientForSession(session, clientId, clientName) {
            session.clientId = clientId;
            session.client.id = clientId;
            session.client.clientType = 0;//只可能从访客变成客户，这里直接写死type变成客户的type
            setupClientDisplayName(session.client, clientName);
            $('#sessionTab_' + session.id + ' .nickname_text', container).attr('title', session.client.name);
            $('#sessionTab_' + session.id + ' .nickname_text', container).html(session.client.name);
            if (session.id == currentSessionId) {
                $('.session_hd .title_name', container).html(session.client.name + ((session.userCount > 2) ? '(' + session.userCount + ')' : ''));
            }
        }

        /**
         * 显示聊天请求接受对话框
         */
        function showRequestDialog(requestId, user, chatRequestToUser) {
            if (chatPanelIsHidden()) {
                $E.openChatPanel();
                $('.chat', container).show();
            }
            var requestType = chatRequestToUser.requestType;
            var tabTitle = i18n.request;
            if (requestType == CHAT_REQUEST_TYPE['clientRequest'])
                tabTitle = i18n.webRequest;
            else if (requestType == CHAT_REQUEST_TYPE['wechatRequest'])
                tabTitle = i18n.wechatRequest;
            else if (requestType == CHAT_REQUEST_TYPE['agentInvite'])
                tabTitle = i18n.invite;
            else if (requestType == CHAT_REQUEST_TYPE['agentTransfer'] || requestType == CHAT_REQUEST_TYPE['agentTransferToQueue'])
                tabTitle = i18n.transfer;

            $('.requestDialog', container).show().css({
                "paddingTop": ($(container).height() - $('.requestDialog .chat-dialog-content', container).height() - 100) / 2
            });

            var nav = requestTabs.find(".ui-tabs-nav"), m = 'request_' + requestId,
              label = tabTitle + '[' + requestId + ']',
              tab = $("<li data-id='" + requestId + "'><a href='#" + m + "'>" + label + "</a></li>"),
              tabContainer = $('<div id="' + m + '" class="request-tab-container" style="padding: 10px;"></div>');
            tabContainer.append(
              '<div class="dialog_bd">' +
              '<div><table>' +
              '<tr><td>' + i18n.name + '</td><td>' + setupClientDisplayName(user) + '</td></tr>' +
              (chatRequestToUser.client ? '<tr><td>' + i18n.clientName + '</td><td>' + setupClientDisplayName(chatRequestToUser.client) + '</td></tr>' : '') +
              (chatRequestToUser.queueName ? '<tr><td>' + i18n.queueName + '</td><td>' + chatRequestToUser.queueName + '</td></tr>' : '') +
              (chatRequestToUser.comments ? '<tr><td>' + i18n.comments + '</td><td>' + chatRequestToUser.comments + '</td></tr>' : '') +
              '</table></div>' +
              '<div class="progress"></div>' +
              '</div>' +
              '<div class="dialog_ft">' +
              '<a href="javascript:;" class="btn btn_primary accept">' + i18n.accept + '</a>' +
              '<a href="javascript:;" class="btn btn_primary reject">' + i18n.reject + '</a>' +
              '</div>');
            $('.accept', tabContainer).one('click', function () {
                $F.log('Chat', 'Request ' + requestId + ' accepted');
                sendRequestResponse(requestId, 'yes');
                closeRequestTab(tab, requestId);
            });
            $('.reject', tabContainer).one('click', function () {
                $F.log('ChatMonitor', 'Request ' + requestId + ' rejected');
                sendRequestResponse(requestId, 'no');
                closeRequestTab(tab, requestId);
            });
            var requestProgress = $('.progress', tabContainer).progressbar({
                max: c.configs.timeoutForAccept,
                value: c.configs.timeoutForAccept,
                create: function (event) {
                    $('.progress .ui-progressbar-value', tabContainer).css({margin: 0, border: 0});
                }
            });

            var updateRequestProgress = function (requestProgress) {
                var value = requestProgress.progressbar("value");
                if (value > 0) {
                    requestProgress.progressbar("value", value - 1);
                    if (value > c.configs.timeoutForAccept / 3 * 2) {
                        $('.progress .ui-progressbar-value', tabContainer).css({background: '#3caf36'});
                    } else if (value > c.configs.timeoutForAccept / 3) {
                        $('.progress .ui-progressbar-value', tabContainer).css({background: '#FFCE42'});
                    } else {
                        $('.progress .ui-progressbar-value', tabContainer).css({background: '#DD5044'});
                    }

                    requestProgressTimer[requestId] = setTimeout(function () {
                        updateRequestProgress(requestProgress);
                    }, 1000);
                } else {
                    sendRequestResponse(requestId, 'timeout');
                    closeRequestTab(tab, requestId);
                }
            }

            tab.data('container', tabContainer);
            tab.appendTo(nav);
            requestTabs.append(tabContainer);
            setTimeout(function () {
                requestTabs.tabs("refresh");
                var tabIdx = $('li', nav).length;
                requestTabs.tabs({
                    active: tabIdx - 1
                });
                $('.request-tab-container', requestTabs).css('height', 'auto');

                updateRequestProgress(requestProgress);
            }, 100);

            function closeRequestTab(tab, requestId) {
                if (requestProgressTimer[requestId]) {
                    clearTimeout(requestProgressTimer[requestId]);
                }

                tab.data("container").remove();
                tab.remove();
                requestTabs.tabs("refresh");
                if ($('li', nav).length === 0) {
                    $('.requestDialog', container).hide();
                }
            }

            notifyMe();
        }

        /**
         * 显示聊天请求接受对话框
         */
        function showCloseSessionDialog(sessionId) {
            $('.closeSessionDialog', container).show().css({
                "paddingTop": ($(container).height() - $('.closeSessionDialog .chat-dialog-content', container).height() - 100) / 2
            });
            var confirmContainer,
              sessionCur = sessionsMap["session" + sessionId],
              closeMessage = c.configs.onAgentSessionCloseMessage ? $F.ognl(c.configs.onAgentSessionCloseMessage, {
                  name: sessionCur.client.name
              }) : i18n.closeSessionConfirm + '[' + sessionCur.client.name + ']';
            if (sessionCur) {
                if (sessionCur.active) {
                    confirmContainer = $(
                      '<div class="chat-dialog-content">' +
                      '<span class="fa-stack fa-lg confirm"><i class="fa fa-circle fa-stack-2x"></i><i class="fa fa-question fa-stack-1x fa-inverse"></i></span>' +
                      '<span style="padding-left: 10px;">' + closeMessage + '</span>' +
                      '</div>' +
                      '<div class="dialog_ft" style="text-align: right;">' +
                      '<a href="javascript:;" class="btn btn_primary end" style="width: 110px;text-align: center;padding: 3px 20px">' + i18n.end + '</a>' +
                      '<a href="javascript:;" class="btn btn_primary close" style="width: 110px;text-align: center;padding: 3px 20px">' + i18n.endAndClose + '</a>' +
                      '</div></div>');
                    $('.end', confirmContainer).on('click', function () {
                        endSession(sessionId);
                        $('.closeSessionDialog', container).hide();
                    });
                    $('.close', confirmContainer).on('click', function () {
                        removeTabAndSession(sessionId);
                        $('.closeSessionDialog', container).hide();
                    });
                } else {
                    confirmContainer = $(
                      '<div class="chat-dialog-content">' +
                      '<span class="fa-stack fa-lg confirm"><i class="fa fa-circle fa-stack-2x"></i><i class="fa fa-question fa-stack-1x fa-inverse"></i></span>' +
                      '<span style="padding-left: 10px;">' + closeMessage + '</span>' +
                      '</div>' +
                      '<div class="dialog_ft" style="text-align: right;">' +
                      '<a href="javascript:;" class="btn btn_primary close" style="width: 110px;text-align: center;padding: 3px 20px">' + i18n.confirm + '</a>' +
                      '</div></div>');
                    $('.close', confirmContainer).on('click', function () {
                        removeTabAndSession(sessionId);
                        $('.closeSessionDialog', container).hide();
                    });
                }
                $('.closeSessionDialog .confirmContainer', container).empty().append(confirmContainer);
            }
        }

        /**
         * 显示消息预览对话框
         * 如果是formattedMsg，则弹出这个消息的预览
         * @param msg
         */
        function showMessagePreviewDialog(msg) {
            $('.messagePreviewDialog', container).show().css({
                "paddingTop": ($(container).height() - $('.messagePreviewDialog .chat-dialog-content', container).height() - 100) / 2
            });

            $('.messagePreviewDialog .dialog_bd', container).empty().append(Tools.parseFormattedMsg(msg));
        }

        /**
         * 截图上传
         * @param mode 这个是截图的类型 0是隐藏当前窗口，1是不隐藏当前窗口
         */
        function capture(mode) {
            mode = mode || 0;
            var fileExtension = 'png',
              now = new Date(),
              tmpFileName = now.getTime() + "." + fileExtension,
              uploadURL = chatServerAddr + '/uploadDataURI';
            $F.log('ChatMonitor - screencut', 'Start screen cut: ' + tmpFileName);
            H5Utils.captureWithoutWS(tmpFileName, mode, function (d) {
                if (d.code == -1) {
                    $F.info(d.message);
                } else {
                    uploadDataURL(d.content, d.tmpFileName, uploadURL);
                }
            }, uploadURL, false);
        }

        function setTypingNotice(notice) {
            $('.session_hd .typing', container).html(i18n.typing);
            if (typingTimer) {//reset last timer to start over
                clearTimeout(typingTimer);
            }
            typingTimer = setTimeout(removeTypingNotice, 10 * 1000);
            if (!typingEffectTimer) {
                typingEffectTimer = setInterval(function () {
                    $('.session_hd .typing', container).css('color', '#' + Math.floor(Math.random() * 16777215).toString(16));
                }, 500);
            }
        }

        function removeTypingNotice() {
            if (typingEffectTimer) {
                clearInterval(typingEffectTimer);
                typingEffectTimer = null;
            }
            $('.session_hd .typing', container).html('');
        }

        function postMessageStart(event, params) {
            if (showAgentAssistIframe && showAgentAssistIframe.id && showAgentAssistIframe.url) {
                const agentAssistIframe = $("#" + showAgentAssistIframe.id).prop('contentWindow');
                if (agentAssistIframe) {
                    if ($CONST.ChatEvent.CHAT_SESSION_CREATED === event) {   //创建会话
                        agentAssistIframe.postMessage({
                            action: "sessionStart",
                            sessionId: params.sessionId, //开始会话ID
                            lang: params.session.client.lang,  //中英文
                            from: params.session.client.targetId, //来源
                            client: {
                                id: params.session.clientId, //客户ID
                                type: params.session.client.clientType, //客户类型 0 登录客户 1 访客
                                name: params.session.client.firstName !== '' ? params.session.client.firstName : params.session.client.alias//客户名称
                            }
                        }, '*');
                    } else if ($CONST.ChatEvent.CHAT_SESSION_CHANGED === event && params.sessionId !== '') {
                        //切换会话
                        agentAssistIframe.postMessage({
                            action: "sessionChange",
                            sessionId: params.sessionId // 会话ID
                        }, '*');
                    } else if ($CONST.ChatEvent.CHAT_SESSION_CLOSED === event) { //结束会话
                        agentAssistIframe.postMessage({
                            action: "sessionEnd",
                            sessionId: params.sessionId // 会话ID
                        }, '*');
                    } else if ($CONST.ChatEvent.NEW_MESSAGE_RECEIVED === event) {
                        agentAssistIframe.postMessage({
                            action: "postMessage",
                            sessionId: params.sessionId, // 会话ID
                            text: params.message.text //需要搜索的消息内容
                        }, '*');
                    }
                }
            }
        }

        /**
         * 监听来自页面的内容
         */
        window.addEventListener('message', function (e) {
            if (e.data.action === 'addMessageToTextarea' && e.data.content.trim() !== '')
                var curSession = sessionsMap["session" + currentSessionId];
            if (curSession && curSession.active) {
                $('.control_panel .content #edit-area', container).text(e.data.content.trim());
            }
        }, false);

        function notifyProjectEvent(event, params) {
            try {
                postMessageStart(event, params);
                project.events.notify(event, params);
            } catch (e) {
                $F.err('ChatMonitor - notifyProjectEvent', e);
            }
        }

        function chatUnload() {
            $F.log('ChatMonitor - unload', 'On window unload');
            if (c.configs.agentExceptionStatus) {
                c.changeToExceptionStatus();
            } else {
                c.logout();
            }
        }

        function setTranslateLanguage(currentSessionId, agentLang, targetLang) {
            callService({
                data: {
                    requestType: 'selectTranslateLanguage',
                    sessionId: currentSessionId,
                    languageAgent: agentLang,
                    languageClient: targetLang
                }
            }).done(function (data) {
                if (data.status === 'success') {
                    var sessionCur = sessionsMap["session" + currentSessionId];
                    sessionCur.languageTo = targetLang;
                }
            }).fail(function (e) {
                $F.err('ChatMonitor - translate', i18n.error.translateFailed);
            });
        }

        //设置工具栏的下来列表语言
        function setLanguageSelect(lang) {
            if (translateAutoEnabled) {
                $('#trans_select').val(lang).trigger("change");
            }
        }

        /**
         * 在现在这种webworker模式下，是否还需要checkPull?
         */
        function startCheckPull() {
            checkPullTimer = setInterval(function () {
                if (lastPullTime && new Date().getTime() - lastPullTime > 15000) {
                    $F.log('ChatMonitor - checkPull', 'Pull error, restart pull');
                    c.worker.postMessage({
                        cmd: 'doPull',
                        params: {
                            timeout: c.configs.timeoutForPull
                        }
                    });
                } else {
                    $F.log('ChatMonitor - checkPull', 'Check pull successful.')
                }
            }, 15000);
        }

        /**
         * 发送转接会议请求
         */
        function sendTCRequest(sendInfo) {
            return new Promise(resolve => {
                callService({
                    data: {
                        requestType: 'send',
                        data: JSON.stringify(sendInfo)
                    }
                }).done(function (jsonResponse) {
                    if (jsonResponse.status === 'success') {
                        var sendResponse = jsonResponse.sendResponse;
                        var chatRequestId = sendResponse.chatRequestId;
                        requestIdsArr[requestIdsArr.length] = chatRequestId;
                        var feedbackMessage = sendResponse.feedbackMessage;
                        appendTextToDiv(formatFeedbackMessage(feedbackMessage));
                        var sessionId = sendResponse.sessionId;
                        if (sessionId) {
                            addMessageToSession(sessionId, {
                                id: "-1",
                                name: null
                            }, {text: formatFeedbackMessage(feedbackMessage), type: MESSAGE_TYPE.SYSTEM});
                        }
                        $('#tcDialog', container).hide();
                        resolve(1);
                    } else {
                        $F.alert(i18n.error.requestFailed);
                        resolve(0);
                    }
                }).fail(function () {
                    $F.alert(i18n.error.requestFailed);
                    resolve(0);
                });
            })
        }

        /**
         * 发送正在输入的通知消息
         */
        function sendTypingNotice() {
            var now = new Date().getTime();
            if ((now - lastTypingNotificationTime) >= (typingNotificationDelay * 1000)) {
                lastTypingNotificationTime = now;
                callService({
                    data: {
                        requestType: 'sendTypingNotification',
                        sessionId: currentSessionId
                    }
                });
            }
        }

        function getIntParam(project, name) {
            return $F.parseInt(project.getParam(name));
        }

        this.userStatusElapseTicker = function (us) {
            const c = this;
            let lastingTime = new Date().getTime() - c.currentUserStatusStartTime;
            if (us.timeout && lastingTime > us.timeout * 1000) {
                $(".header .display_name .name_extra", c.container).addClass('timeout');
            }
            userStatusTimer = setTimeout(function () {
                $(".header .display_name .user_status", c.container).text(us.userStatus + ': ' + Tools.getFormattedLasting(lastingTime, 1));
                c.userStatusElapseTicker(us);
            }, 1000);
        };

        this.setUserStatus = function () {
            var c = this;
            $(".header .display_name .name_extra", c.container).removeClass('timeout');
            c.currentUserStatusStartTime = new Date().getTime();
            if (userStatusTimer) {
                clearTimeout(userStatusTimer);
            }
            var us = c.userStatus[c.currentUserStatus];
            $('.chat-monitor .user_status_menu ul>li>a .selected', c.container).remove();
            $('.chat-monitor .user_status_menu ul>li[data-status=' + c.currentUserStatus + ']>a', c.container).append('<i class="selected fa fa-check" />');
            if (c.currentUserStatus !== USER_STATUS.ONLINE) {
                $(".header .display_name .user_status", c.container).text(us.userStatus).removeClass('online');
                c.userStatusElapseTicker(us);
            } else {
                $(".header .display_name .user_status", c.container).text(us.userStatus).addClass('online');
            }
        };

        this.hideUserStatusMenu = function () {
            clearTimeout(this.statusChangeHoverTimer);
            $('.chat-monitor .user_status_menu', this.container).css('left', 195).hide();
        };

        this.listWaitingRequests = function (allQueues = false) {
            return callService({
                data: {
                    requestType: "listWaitingRequests",
                    allQueues: allQueues
                }
            });
        };

        /**
         * 预览Formatted消息
         * @param msg
         */
        this.previewFormattedMessage = function (msg) {
            $('.messagePreviewDialog .confirm', container).data('sessionId', currentSessionId).data('msg', msg);
            if (Tools.isFormattedMsg(msg)) {
                showMessagePreviewDialog(msg);
            } else {
                $F.notify(i18n.error.normalMsgNeedNotPerview, 0);
            }
        };

        this.logoutAndClose = function () {
            this.closeChat();
            this.logout().finally(() => {
                notifyProjectEvent($CONST.ChatEvent.CHAT_LOGGED_OUT || 'CHAT_LOGGED_OUT');
            });
        };

        this.logout = function () {
            return new Promise((resolve, reject) => {
                callService({
                    url: 'logout_.do'
                }).done(function () {
                    $F.log("ChatMonitor - logout", "logout success");
                    resolve();
                }).fail(function (jqXHR) {
                    $F.log('ChatMonitor - logout', 'logout failed', jqXHR);
                    $F.alert(i18n.error.loggedOutFailed + ': ' + jqXHR.status + ' ' + jqXHR.statusText);
                    reject();
                });
            })
        };

        this.closeChat = function () {
            c.logined = false;
            $('.c_chat i').css('color', '#afb5b9')
            for (var requestId in requestProgressTimer) {
                if (requestProgressTimer[requestId]) {
                    clearTimeout(requestProgressTimer[requestId]);
                }
            }
            if (userWaitingTimer) {
                clearTimeout(userWaitingTimer);
            }

            if (checkPullTimer) {
                clearInterval(checkPullTimer);
            }
            c.worker.terminate();
            $(window).off('unload', chatUnload);
            c.pluginDom.remove().html('');
            //清除instance缓存
            project.removeModuleInstance($CONST.ModuleName.CHAT);
            project.events.remove('ChatMonitor');
            $.contextMenu('destroy', '.chat-monitor .message.me .bubble_cont.ns');
            $.contextMenu('destroy', '.chat-monitor .message:not(.me,.translated,.no-translate) .plain');
            if (!this.parameters.fromDyn) {
                //收起右边页
                $E.openChatPanel();
            }
        };

        var init = function () {
            var busyId = $F.busyShow(i18n.dyn.loading + ': ' + i18n.loggingChat),
              startPaste = false;
            compatibleOldNgsFunctions(c.project); //兼容老版本的ngs
            if (c.project.getParam('CHALOC') === 'embed') {
                $('.configDialog .swapRLContainer', container).hide();
            }
            $(window).on('unload', chatUnload);
            // 初始化title闪烁
            c.originalTitle = document.title;
            $(window).on('focus', () => {
                if (c.blinkTitleTimer) {
                    clearInterval(c.blinkTitleTimer);
                    c.blinkTitleTimer = undefined;
                    document.title = c.originalTitle;
                }
            });
            //刚进页面时候，禁止输入
            $('.btn_send', container).attr('disabled', true);
            $('.control_panel .content #edit-area', container).attr('contenteditable', false);
            $('.toolbar', container).css("display", "none");
            $('.chat_face,.chat_screencut,.chat_pic,.chat_push_rating,.chat_translate_container', container).css("display", "none");

            //点击其他位置时候，隐藏所有popup菜单
            $('.chat-monitor', container).click(function () {
                $('#mmpop_system_menu', container).hide();
                c.hideUserStatusMenu();
                $('#mmpop_emoji_panel', container).hide();
                $('.session_more_menu', container).hide();
            });

            //注册发送按钮
            $('.control_panel .btn_send', container).click(function () {
                if (c.sending) return;
                var content = $('.control_panel .content #edit-area', container).html();
                if (content) {
                    if (maxSendingWordLength > 0 && content.length > maxSendingWordLength) { // 超过最大发送消息长度
                        $F.alert(i18n.error.maxWordLengthExceed.format(maxSendingWordLength));
                        return;
                    }
                    try {
                        c.sending = true;
                        var sendContent = content;
                        if (Tools.isFormattedMsg(content)) {// 格式化消息不去做特殊处理
                            sendContent = content = $('.control_panel .content #edit-area', container).text();
                        } else {
                            $("<div>").append(sendContent).find('img.qqemoji').each(function () {
                                var regexp = new RegExp($("<div>").append(this).html().replace("[", "\\[").replace("]", "\\]"), "gi");
                                var emojiText = $(this).attr('text');
                                //emojiText = emojiText.substring(0, emojiText.indexOf("_"));
                                sendContent = sendContent.replace(regexp, '[' + emojiText + ']');
                            });
                            $("<div>").append(sendContent).find('img.standard-emoji').each(function () {
                                var regexp = new RegExp($("<div>").append(this).html(), "gi");
                                var emojiText = $(this).attr('text');
                                sendContent = sendContent.replace(regexp, '[' + emojiText + ']');
                            });

                            //禁用词过滤
                            if(chatSensitiveSend && c.forbidWords && c.forbidWords.length>0){
                                var forbidWord = false, alertForbidContent = content;
                                c.forbidWords.forEach(function (dw) {
                                    if (content.indexOf(dw) > -1) {
                                        forbidWord = true;
                                        var dwReg = new RegExp(dw, 'g');
                                        alertForbidContent = alertForbidContent.replace(dwReg, '<span class="dw-highlight">' + dw + '</span>');
                                    }
                                });
                                if(forbidWord){
                                    return Tools.confirmPrompt(i18n.prohibitSendingProhibitedWords + ': \n<div>' + alertForbidContent + '</div>', function () {
                                        c.sending = false;
                                    });
                                }
                            }

                            //脏词过滤
                            if (dirtyWordsScanEnabled) {
                                if (c.dirtyWords) {
                                    var findDirtyWord = false, alertContent = content;
                                    c.dirtyWords.forEach(function (dw) {
                                        if (content.indexOf(dw) > -1) {
                                            findDirtyWord = true;
                                            var dwReg = new RegExp(dw, 'g');
                                            alertContent = alertContent.replace(dwReg, '<span class="dw-highlight">' + dw + '</span>');
                                        }
                                    });
                                    if (findDirtyWord) {
                                        return Tools.confirm(i18n.sendingConfirm + ': \n<div>' + alertContent + '</div>', function () {
                                            sendMessage(sendContent, currentSessionId, content, undefined, function () {
                                                $('.control_panel .content #edit-area', container).html("");
                                                c.sending = false;
                                            }, function () {
                                                c.sending = false;
                                            });
                                        }, function () {
                                            c.sending = false;
                                        });
                                    }
                                }
                            }

                            if (editImageAfterPaste) { // 如果开启了编辑粘贴进来的图片的话，需要在发送之前再把图片的url改成真正要发的url
                                $("<div>").append(sendContent).find('img[data-from=elite]').each(function () {
                                    var regexp = new RegExp(Tools.parseForRegexp($("<div>").append(this).html()), "gi");
                                    sendContent = sendContent.replace(regexp, '<img src="' + $(this).attr('data-url') + '" />');
                                })
                            }

                        }

                        sendMessage(sendContent, currentSessionId, content, undefined, function () {
                            $('.control_panel .content #edit-area', container).html("");
                            c.sending = false;
                        }, function (data, $domMessage) {
                            c.sending = false;
                            $('.failed', $domMessage).css("display", 'inline-block');
                            $('.failed', $domMessage).css("display", 'inline-block').one("click", function () {
                                const session = sessionsMap["session" + currentSessionId];
                                if (session.active) {
                                    $($domMessage).remove();
                                    sendMessage(sendContent, currentSessionId, content, undefined, function () {
                                        c.sending = false;
                                    }, function () {
                                        c.sending = false;
                                        $('.failed', $domMessage).css("display", 'inline-block');
                                    });
                                }
                            });
                        });
                    } catch (e) {
                        $F.err('Send Message Error: ' + e.message)
                    } finally {
                        c.sending = false;
                    }
                }
            });

            //注册enter发送还是ctrl+enter发送切换按钮
            $('.control_panel .btn_send_switcher', container).click(function () {
                $('.control_panel .send_switcher_ul', container).toggle();
            });

            $('.control_panel .send_switcher_ul li', container).hover(function () {
                $(this).addClass('active');
            }, function () {
                $(this).removeClass('active');
            });

            $('.control_panel .send_switcher_ul li', container).click(function () {
                sendType = $(this).attr('data-type');
                $('.control_panel .action .desc', container).text($(this).text());
                $('.control_panel .send_switcher_ul', container).hide();
            });


            //监听编辑区，按键事件
            $('.control_panel .content #edit-area', container).on({
                'keydown': function (event) {
                    //回车事件
                    if (event.keyCode === 13) {
                        if (!$('.chat-suggestion', container).is(':hidden')) {
                            if ($('.chat-suggestion li.selected', container).length > 0) {
                                $('.chat-suggestion li.selected', container).trigger('click');
                            } else {
                                $('.chat-suggestion', container).hide();
                            }
                        } else {
                            if (sendType == 0) {
                                if (event.ctrlKey || event.shiftKey || event.altKey || event.metaKey) {
                                    var n = "<br>";
                                    if (window.getSelection) {
                                        var r = window.getSelection().focusNode.nextSibling;
                                        do
                                            if (!r || r.nodeValue || "BR" === r.tagName)
                                                break;
                                        while (r = r.nextSibling);
                                        r || (n += n)
                                    }
                                    Tools.appendToEditDiv(n);
                                    $(this)[0].scrollTop = $(this)[0].scrollHeight;
                                } else {
                                    $('.control_panel .btn_send').click();
                                }
                            } else {
                                if (event.ctrlKey || event.shiftKey || event.altKey || event.metaKey) {
                                    $('.control_panel .btn_send').click();
                                } else {
                                    var n = "<br>";
                                    if (window.getSelection) {
                                        var r = window.getSelection().focusNode.nextSibling;
                                        do
                                            if (!r || r.nodeValue || "BR" === r.tagName)
                                                break;
                                        while (r = r.nextSibling);
                                        r || (n += n)
                                    }
                                    Tools.appendToEditDiv(n);
                                    $(this)[0].scrollTop = $(this)[0].scrollHeight;
                                }
                            }
                        }
                        event.preventDefault();
                    }
                    //快捷键 alt+0到9 ctrl+alt+0到9
                    if (event.keyCode >= 48 && event.keyCode <= 57) {
                        if (event.altKey) {
                            var key = 'alt';
                            if (event.ctrlKey && event.altKey) {
                                key = 'ctrl+alt';
                            }
                            key = key + '+' + (event.keyCode - 48);
                            $F.log('ChatMonitor - keydown', 'key: ' + key);
                            notifyProjectEvent($CONST.ChatEvent.SHORTCUT, {
                                sessionId: currentSessionId,
                                key: key
                            });
                        }
                    }

                    // ESC
                    if (event.keyCode === 27) {
                        $('.chat-suggestion', container).hide();
                    }
                    // 箭头上，箭头下
                    if (event.keyCode === 38 || event.keyCode === 40) {
                        if (!$('.chat-suggestion', container).is(':hidden')) {
                            event.stopPropagation();
                            event.preventDefault();
                            var lis = $('.chat-suggestion li', container),
                              selectedLi = $('.chat-suggestion li.selected', container);
                            if (event.keyCode === 40) {
                                if (selectedLi.length > 0) {
                                    lis.removeClass('selected');
                                    let index = lis.index(selectedLi) + 1;
                                    index = index % lis.length;
                                    lis.eq(index).addClass('selected');
                                } else {
                                    lis.first().addClass('selected');
                                }
                            }
                            if (event.keyCode === 38) {
                                if (selectedLi.length > 0) {
                                    lis.removeClass('selected');
                                    let index = lis.index(selectedLi) - 1;
                                    index = index % lis.length;
                                    lis.eq(index).addClass('selected');
                                } else {
                                    lis.last().addClass('selected');
                                }
                            }
                        }
                    }

                    //截图快捷键
                    if (event.shiftKey && event.altKey && event.keyCode === 90) {
                        //隐藏当前窗口截图
                        capture();
                        event.stopPropagation();
                        event.preventDefault();
                    } else if (event.shiftKey && event.altKey && event.keyCode === 65) {
                        //不隐藏当前窗口截图
                        capture(1);
                        event.stopPropagation();
                        event.preventDefault();
                    }
                },
                'keyup': function (e) {
                    //backspace
                    if (e.keyCode === 8) {//当删除内容时候，如果是换行后删除换行，需要多删除一个br
                        var html = $('.control_panel .content #edit-area', container).html();
                        if (html.endsWith('<br>')) {
                            $('.control_panel .content #edit-area', container).html('');
                            Tools.appendToEditDiv(html.substring(0, html.length - 4));
                        }
                    }
                },
                'drop': function (event) {
                    // 防止拖拽内容进输入框
                    event.preventDefault();
                    event.stopPropagation();
                },
                click: function (e) {
                    var childNodes = e.target.childNodes;
                    if (childNodes.length > 1) {
                        var lastNodes = childNodes[childNodes.length - 1];
                        if ('IMG' === lastNodes.tagName) {
                            if (e.offsetX > lastNodes.offsetWidth + lastNodes.offsetLeft) {
                                if (e.offsetY > lastNodes.offsetTop - lastNodes.offsetHeight) {
                                    document.execCommand('selectAll', false, null);
                                    document.getSelection().collapseToEnd();
                                }
                            }
                        }
                    }
                },
                //响应paste事件，获取纯文本数据，过滤html的内容（chrome可用）
                'paste': function (e) {
                    const csId = currentSessionId;
                    const clipboardData = e.originalEvent.clipboardData || window.clipboardData;
                    if (clipboardData && clipboardData.items) {
                        // 循环处理items
                        // 如果items里有文件，则上传第一个，并结束
                        // 如果items里没有文件，则获取text
                        // 禁止默认粘贴行为，避免图片内容带有dataURI，造成消息内容过大
                        let findFile = false;
                        $.each(clipboardData.items, (i, item) => {
                            if (item.kind === 'file' && item.type.match('^image/')) {
                                e.stopPropagation();
                                e.preventDefault();
                                const file = item.getAsFile();
                                if (file) {
                                    findFile = true;
                                    uploadOneImage(file, csId);
                                    return false;
                                }
                            }
                        });
                        if (findFile)
                            return;
                    }

                    //如果都没找到剪贴板中有文件
                    const pastedData = clipboardData.getData('Text');
                    if (pastedData) {
                        if (document.body.createTextRange) {
                            // ie11
                        } else {
                            e.stopPropagation();
                            e.preventDefault();
                            document.execCommand('insertText', false, pastedData);
                        }
                    } else {
                        e.stopPropagation();
                        e.preventDefault();
                    }
                }
            });


            const uploadOneImage = (file, sessionId) => {
                if (uploadDisabled) {// 如果禁用上传，则直接return
                    return;
                }
                if (startPaste) return; // 避免重复粘贴
                startPaste = true;
                const tmpFileName = new Date().getTime() + ".png";
                const fd = new FormData();
                fd.append('file', file);
                fd.append('fileName', tmpFileName);
                $.ajax({
                    type: 'POST',
                    url: chatServerAddr + '/uploadh5',
                    data: fd,
                    processData: false,
                    contentType: false,
                    xhrFields: {
                        withCredentials: true
                    }
                }).done(function (data) {
                    if (data.status === 'success') {
                        if (data.url) {
                            var displayUrl = chatServerHost + data.url,
                              content = '<img data-from="elite" src = "' + data.url + '" >',
                              displayContent = '<img data-from="elite" src = "' + displayUrl + '" style="max-width: 300px;max-height: 300px;vertical-align: baseline" data-url="' + data.url + '">';
                            $F.log('ChatMonitor - uploadh5', 'Upload done, download path:' + displayUrl);
                            if (editImageAfterPaste) {
                                Tools.appendToEditDiv(displayContent);
                                Tools.addImageClick($('#edit-area'), chatServerAddr)
                            } else {
                                Tools.confirm(i18n.sendImageConfirm + '<div>' + displayContent + '</div>', function () {
                                    sendMessage(content, sessionId, displayContent);
                                });
                            }
                        } else {
                            $F.log('ChatMonitor - uploadh5', 'Upload done, download failed:' + data.msg);
                            $F.alert(i18n.error.uploadFailed + ': ' + (data.msg || i18n.error.serverError));
                        }
                    } else {
                        $F.alert(i18n.error.uploadFailed + ': ' + data.message);
                    }
                }).always(function () {
                    startPaste = false;
                });
            };

            // 输入框建议检索
            if (project.esc && suggestionSearchEnabled) {
                $('.control_panel .content #edit-area', container).on('keyup', function (e) {
                    if (!customSuggestionEnabled) {
                        return;
                    }
                    if (e.keyCode === 13 || e.keyCode === 38 || e.keyCode === 40 || e.keyCode === 27) {
                        return;
                    }
                    if (suggestionSearchTimer) {
                        clearTimeout(suggestionSearchTimer);
                        suggestionSearchTimer = null;
                    }
                    suggestionSearchTimer = setTimeout(function () {
                        var content = $('.control_panel .content #edit-area', container).text();
                        //有输入内容，且内容在suggestionMaxWordLength个字以内（内容多于suggestionMaxWordLength个字认为他自己想输入，不想用建议）
                        if (content && content.length < suggestionMaxWordLength) {
                            //当上次搜索内容和这次一样，且结果还显示着的时候，就不再次去查询了
                            if (lastSearchContentForSuggestion === content) {
                                if (!$('.chat-suggestion', container).is(':hidden')) {
                                    return;
                                }
                            }
                            lastSearchContentForSuggestion = content;
                            project.esc.search({
                                "query": {
                                    "bool": {
                                        "should": {"terms": {"user_id": [$E.staff.id, ""]}},
                                        "must": {"match": {"content": content}}
                                    }
                                }
                            }, function (resp) {
                                if (resp.hits.hits && resp.hits.hits.length > 0) {
                                    var suggestionUl = $('<ul>');
                                    $.each(resp.hits.hits, function (i, hit) {
                                        var li = $('<li>');
                                        if (i === 0) {
                                            li.addClass('first');
                                        }
                                        if (i === resp.hits.hits.length - 1) {
                                            li.addClass('last');
                                        }
                                        if (hit._source.title) {
                                            li.append('<span class="title">' + hit._source.title + '</span>');
                                        }
                                        li.append($('<div>').append(hit._source.content).text()).data('content', hit._source.content);
                                        li.on('click', function () {
                                            $('.control_panel .content #edit-area', container).html('');
                                            $('.control_panel .content #edit-area', container).focus();
                                            Tools.appendToEditDiv($(this).data('content'));
                                            $('.chat-suggestion', container).hide();
                                        });
                                        suggestionUl.append(li);
                                    });
                                    $('.chat-suggestion ul', container).remove().html('');
                                    $('.chat-suggestion', container).append(suggestionUl);
                                    $('.control_panel .content #edit-area', container).one('click', function () {
                                        $('.chat-suggestion', container).hide();
                                    });
                                    $('.chat-suggestion', container).show();
                                }
                            }, function (err) {
                                $F.log('Search error:', err);
                            }, 'chat', 1);
                        } else {
                            $('.chat-suggestion', container).hide();
                        }
                    }, 1000);
                });
            }

            $('.control_panel .content #edit-area', container).on('keyup', tools.debounce(function () {
                sendTypingNotice();
            }, 500, false));

            //注册表情按钮
            $('.chat_face', container).click(function (e) {
                e.stopPropagation();
                $('#mmpop_emoji_panel', container).toggle();
            });

            //是否显示默认qq表情与emoji表情
            if (CHAEMO === 1) {
                $('.chat-monitor .exp_hd .qq', container).hide();
                $('.chat-monitor .exp_bd .qq', container).hide();
                $('.chat-monitor .exp_hd .emoji', container).addClass('active');
                $('.chat-monitor .exp_bd .emoji', container).addClass('active');
            } else if (CHAEMO === 2) {
                $('.chat-monitor .exp_hd .emoji', container).hide();
                $('.chat-monitor .exp_bd .emoji', container).hide();
                $('.chat-monitor .exp_hd .qq', container).addClass('active');
                $('.chat-monitor .exp_bd .qq', container).addClass('active');
            } else if (CHAEMO === 3) {
                $('.chat-monitor .exp_hd .qq', container).hide();
                $('.chat-monitor .exp_bd .qq', container).hide();
                $('.chat-monitor .exp_hd .emoji', container).hide();
                $('.chat-monitor .exp_bd .emoji', container).hide();
            } else if (CHAEMO === 4) {
                //qq和emoji位置互换
                $('.chat-monitor .exp_hd .emoji', container).after($('.chat .exp_hd .qq', container));
                $('.chat-monitor .exp_bd .emoji', container).after($('.chat .exp_bd .qq', container));
                $('.chat-monitor .exp_hd .emoji', container).addClass('active');
                $('.chat-monitor .exp_bd .emoji', container).addClass('active');
                $('.chat-monitor .exp_hd .qq', container).removeClass('active');
                $('.chat-monitor .exp_bd .qq', container).removeClass('active');
            }

            //装载自定义表情
            $.getJSON('js/plugins/chat/custom-emoji.json').done(function (data) {
                if (data && data.length > 0) {
                    $('<li class="exp_hd_item" data-index="3"><a href="javascript:;">' + i18n.customEmoji + '</a></li>').appendTo($('.chat .exp_hd', container));
                    var cemos = '<div class="exp_cont active" data-index="3"><div class="custom_face">';
                    data.forEach(function (cemo) {
                        var cemoDisplayUrl = cemo.url;
                        if (!cemoDisplayUrl.toLowerCase().startsWith('http')) {
                            if (!cemoDisplayUrl.startsWith('/'))
                                cemoDisplayUrl = '/' + cemoDisplayUrl;
                            if (cemoDisplayUrl.startsWith(chatServerName)) {
                                cemoDisplayUrl = chatServerHost + cemoDisplayUrl;
                            } else {
                                cemoDisplayUrl = chatServerAddr + cemoDisplayUrl;
                            }
                        }
                        cemos += '<a type="custom" class="face customface" data-src="' + cemo.url + '"><img src="' + cemoDisplayUrl + '" /></a>';
                    });
                    cemos += '</div></div>';
                    $(cemos).appendTo($('.chat-monitor .exp_bd.scroll-content', container));
                    $('#mmpop_emoji_panel .custom_face a', container).click(function (e) {
                        e.stopPropagation();
                        $('.control_panel .content #edit-area', container).append('<img class="custom-emoji" data-src="' + $(this).attr('data-src') + '" src="' + $(this).find('img').attr('src') + '" >');
                    })
                }
            }).always(function () {
                //装载多表情tab
                $('.exp_hd_item', container).click(function (e) {
                    e.stopPropagation();
                    $('.exp_hd_item', container).removeClass('active');
                    $(this).addClass('active');
                    $('.exp_cont', container).removeClass('active');
                    $('.exp_cont[data-index=' + $(this).attr('data-index') + ']', container).addClass('active');
                });
            });

            //注册具体每个qq表情点击逻辑
            $('#mmpop_emoji_panel .qq_face a', container).click(function (e) {
                e.stopPropagation();
                var index = $(this).attr('class').replace('face qqface', '');
                var text = $(this).attr('title');
                $('.control_panel .content #edit-area', container).append('<img class="qqemoji qqemoji' + index + '" text="' + text + '" src="js/plugins/chat/images/spacer.gif" >');
            });
            //注册每个标准emoji表情点击逻辑
            $('#mmpop_emoji_panel .emoji_face a', container).click(function (e) {
                e.stopPropagation();
                var index = $(this).attr('class').replace('face emojiface', '');
                var text = $(this).attr('title');
                $('.control_panel .content #edit-area', container).append('<img class="standard-emoji standard-emoji' + index + '" text="' + text + '" src="js/plugins/chat/images/spacer.gif" >');
            });

            $.getJSON('js/plugins/chat/custom-icon.json').done(function (data) {
                c.customIcons = data;
            });

            //注册截图按钮
            $('.chat_screencut', container).click(function (e) {
                capture();
            });
            //初始化按钮的tooltip
            $('.chat_screencut', container).tooltip({
                show: {
                    delay: 500
                },
                content: '<div style="color:#343e4a;"><span style="font-weight: bold">' + i18n.capture + '</span><br><span style="font-size: 12px">' +
                  i18n.captureCurrentPage + '(alt+shift+a)</span><br><span style="font-size: 12px">' +
                  i18n.captureMinimumCurrentPage + '(alt+shift+z)</span><br><span style="font-size: 12px">' +
                  i18n.captureWin10Shortcut + '</span></div>'
            });

            //注册附件按钮
            $('.chat-monitor .chat_pic', container).click(function (e) {
                var form = $('.chat-monitor form#chat_upload_form'),
                  input = $("input[type='file']", form);

                input.off('change').on('change', function () {
                    var _fileName = $.trim(input.val());
                    if (!_fileName) {// 提交前的再次检测
                        //ie11里面会触发两次change，第二次文件名变成空时候也会触发一次，所以这里提示不需要了，空时候就不处理即可。
                        //$F.alert('没有选择上传的文件');
                    } else {
                        var csId = currentSessionId;
                        var sessionCur = sessionsMap["session" + currentSessionId];
                        let clientMessageId = '_message-' + new Date().getTime()
                          , $domMessage = '.chat-monitor .clearfix[data-state=' + clientMessageId + ']'
                          , sendTime = 0;
                        var uploadRet = form.upload({
                            clearForm: true,
                            url: chatServerAddr + '/uploadh5',
                            upMaxSize: 0,
                            beforeSend: function () {
                                sendTime = setTimeout(function () {
                                    let message = addMessageToSession(csId, {
                                        id: c.configs.agentId,
                                        name: c.staff.displayName
                                    }, {
                                        stateId: clientMessageId,
                                        text: '<img src="js/plugins/chat/images/loading.gif"/>',
                                        translate: false
                                    }, new Date().format('YYYY-MM-dd HH:mm:ss'));
                                    message.revokable = true;
                                    appendTextToDiv(getDisplayMessage(message, sessionCur));
                                    $('.nickname', $domMessage).remove();
                                }, 1000)
                            },
                            complete: function () {
                                if (sendTime) clearTimeout(sendTime)
                                if ($($domMessage)[0]) {
                                    $($domMessage).remove();
                                }
                            },
                            showError: false,
                            allows: sessionCur.fileAcceptExtensions || c.configs.fileAcceptExtensions,
                            xhrFields: {
                                withCredentials: true
                            },
                            success: function (data) {
                                form[0].reset();
                                var handleUploadResponse = (data) => {
                                    if (data.status === 'success') {
                                        var attachURL = chatServerHost + data.url;
                                        var content, displayContent;
                                        var fName = data.name;
                                        if (!fName) {// 兼容老版本chat（这时候多文件上传会有问题）
                                            fName = _fileName.replace(/\\/gi, '/');
                                            fName = fName.substring(fName.lastIndexOf('/') + 1);
                                        }
                                        if ($F.isImage(fName)) {
                                            displayContent = '<img data-from="elite" src = "' + attachURL + '" title = "' + fName + '">';
                                            content = '<img data-from="elite" src = "' + data.url + '" title = "' + fName + '">';
                                        } else if (fName.toLowerCase().endsWith('.mp4')) {
                                            displayContent = '<video src="' + attachURL + '" controls></video>';
                                            content = '<video src="' + data.url + '" data-name="' + fName + '" data-size="' + data.size + '" controls></video>';
                                        } else {
                                            displayContent = '<div class="message-file" data-url="' + attachURL + '" data-name="' + fName + '"></div>';
                                            content = '<a data-from="elite" href = "' + data.url + '" target = "_blank" class="attachment" data-size="' + data.size + '">' + fName + '</a>';
                                        }
                                        sendMessage(content, csId, displayContent);
                                    } else {
                                        $F.alert(i18n.error.uploadFileFailed + ': ' + data.message);
                                    }
                                };

                                if (data.files && data.files.length > 0) {
                                    data.files.forEach(d => {
                                        handleUploadResponse(d);
                                    })
                                } else {
                                    handleUploadResponse(data);
                                }
                            },
                            error: function () {
                                $F.alert(i18n.error.uploadFileFailed);
                            }
                        });
                        if (uploadRet.code < 0) {
                            $F.alert(i18n.error.uploadFileFailed + ': ' + uploadRet.message);
                        }
                    }
                }).click();
            });

            $('.chat_push_rating', container).click(function () {
                var sessionCur = sessionsMap["session" + currentSessionId];
                if (sessionCur) {
                    var pr = function () {
                        callService({
                            data: {
                                requestType: 'pushRating',
                                sessionId: sessionCur.id
                            }
                        }).done(function (data) {
                            if (data && data.status === "success") {
                                sessionCur.hasPushedRating = true;
                                sessionCur.pushRatingCount++;
                                $('.chat_push_rating', container).addClass('rated');
                                var feedback = formatFeedbackMessage(i18n.feedback.hasPushedRatingMessage.format(sessionCur.pushRatingCount));
                                addMessageToSession(sessionCur.id, {id: "-1", name: null}, {
                                    text: feedback,
                                    type: MESSAGE_TYPE.SYSTEM
                                }, undefined);
                                if (currentSessionId == sessionCur.id) {
                                    appendTextToDiv(feedback);
                                }
                            } else {
                                $F.err('ChatMonitor - pushRating', i18n.error.pushRatingFailed);
                            }
                        }).fail(function () {
                            $F.err('ChatMonitor - pushRating', i18n.error.pushRatingFailed);
                        });
                    };
                    if (pushRatingDirectly) {
                        pr();
                    } else {
                        Tools.confirm((sessionCur.pushRatingCount > 0 ? i18n.pushRatingConfirmHasPushed.format(sessionCur.pushRatingCount) : '') + i18n.pushRatingConfirm + '[' + sessionCur.client.name + ']', function () {
                            pr();
                        });
                    }
                }
            });

            //语言选择触发事件
            $("#trans_select").change(function (data) {
                if (translateAutoEnabled) {
                    var targetLang = $('.trans_to', container).val();
                    if (targetLang) {
                        setTranslateLanguage(currentSessionId, $.cookie('chat.translateTo') || 'zh', targetLang);
                    }
                }
            })

            $('.chat_translate', container).click(function () {
                var targetLang = $('.trans_to', container).val(),
                  content = $('.control_panel .content #edit-area', container).html();
                if (targetLang && targetLang.trim()) {
                    if (content && content.trim()) {
                        callService({
                            data: {
                                requestType: 'translate',
                                text: content,
                                targetLang: targetLang
                            }
                        }).done(function (data) {
                            if (data.status === "success") {
                                $('.control_panel .content #edit-area', container).html(data.text);
                            } else {
                                $F.err('ChatMonitor - translate', i18n.error.translateFailed + ': ' + data.message);
                            }
                        }).fail(function (e) {
                            $F.err('ChatMonitor - translate', i18n.error.translateFailed);
                        });
                    } else {
                        $F.notify(i18n.error.emptyInputNoNeedTranslate, 0);
                    }
                } else {
                    $F.notify(i18n.error.emptyTransforTarget, 0);
                }

            })

            $('.chat_refresh', container).click(function () {
                searchSessionMessage(null, true, currentSessionId)
            })

            $('.session_list .session_refresh_btn', container).click(function (e) {
                searchStaffSessions(null, currentStaffId, true)
            })

            //注册系统菜单逻辑
            $('.chat_add', container).click(function (e) {
                e.stopPropagation();
                clearTimeout(c.statusChangeHoverTimer);
                c.hideUserStatusMenu();
                $('#mmpop_system_menu', container).toggle();
            });
            $(".header .display_name .user_status", container).click(function (e) {
                e.stopPropagation();
                if (c.configs.allowAgentStatusChange === 'false') {
                    return;
                }
                if ($('#mmpop_system_menu', container).css('display') === 'none') {
                    if ($('.chat-monitor .user_status_menu', container).css('display') === 'none') {
                        $('.chat-monitor .user_status_menu', container).css('left', 20).show();
                    } else {
                        c.hideUserStatusMenu();
                    }
                }
            });
            $('#mmpop_system_menu .status-change', container).hover(function () {
                if ($('.chat-monitor .user_status_menu', container).css('display') === 'none') {
                    c.statusChangeHoverTimer = setTimeout(function () {
                        $('.chat-monitor .user_status_menu', container).show();
                    }, 500);
                } else {
                    clearTimeout(c.statusChangeHoverTimer);
                }
            }, function () {
                if ($('.chat-monitor .user_status_menu', container).css('display') === 'none') {
                    clearTimeout(c.statusChangeHoverTimer);
                } else {
                    c.statusChangeHoverTimer = setTimeout(function () {
                        c.hideUserStatusMenu();
                    }, 1000);
                }
            });

            $('.take-over', container).click(function (e) {
                // chatMonitorPull = false
                if (takeOverArray.indexOf(currentSessionId) === -1) {
                    callService({
                        url: "admin/sessionListForMonitor",
                        data: {
                            action: "takeover",
                            sessionId: currentSessionId,
                            from: 'h5',
                            token: c.project.token,
                            ds: $E.dataService.key
                        }
                    }).done(function (data) {
                        if (data.code === 200) {
                            $F.notify('接管成功');
                            takeOverArray.push(currentSessionId)
                            $('.invite, .transfer, .transferToQueue, .close-session', container).show();
                            $('.take-over', container).hide()
                        }
                        // if (data.code === 200) {
                        //     userWaitingTimer = setTimeout(function () {
                        //         userWaitingElapseTicker(c);
                        //     }, 1000);
                        //     c.worker.postMessage({
                        //         cmd: 'start',
                        //         params: {
                        //             url: chatServerAddr + '/' + tools.ajaxURL,
                        //             data: {
                        //                 requestType: 'keep'
                        //             }
                        //         }
                        //     });
                        //
                        //     c.worker.addEventListener('message', e => {
                        //         if (e.data.action === 'pull') {
                        //             if (c.logined) {
                        //                 pullFromServer(c);
                        //             }
                        //         }
                        //     }, false);
                        //
                        //     c.worker.postMessage({
                        //         cmd: 'doPull',
                        //         params: {
                        //             timeout: c.configs.timeoutForPull
                        //         }
                        //     });
                        //
                        //     //开始pull检查
                        //     startCheckPull();
                        // }
                    }).fail(function (xhr) {
                        $F.alert(i18n.error.loggedInChatFailed);

                    });
                }
            })

            $('.close-session', container).click(function () {
                endSession(currentSessionId);
            })

            $('#tcDialog .chat-dialog-close', container).click(function () {
                $('#tcDialog', container).hide();
            });

            $('#tcDialog .confirm', container).click(function () {
                if (c.handlingTC) return;
                c.handlingTC = true;
                var comments = $('#tcDialog .comments .comments-editor', container).text();
                var sendInfo = {
                    actionType: currentTIR,
                    senderId: c.configs.agentId,
                    sessionId: currentSessionId,
                    comments: comments
                };
                if (currentTIR === 'agentTransferToQueue') {
                    var selectedQueueId = $('#tcDialog .chat-queue-select option:selected').val();
                    if (selectedQueueId == -1) {
                        c.handlingTC = false;
                        return $F.alert(i18n.plzChooseAQueue);
                    }
                    sendInfo.queueId = selectedQueueId;
                } else {
                    var selectedAgent = $("#tcDialog .contact_item:has(i.web_wechat_choose_green)", container);
                    if (selectedAgent.length === 0) {
                        c.handlingTC = false;
                        $F.alert(i18n.plzChooseAnAgent);
                        return;
                    }
                    var receiverId = selectedAgent.attr('data-id');
                    sendInfo.receiverId = receiverId;
                    var selectedQueueId = $('#tcDialog .chat-queue-select option:selected').val();
                    if (selectedQueueId != -1) {
                        sendInfo.queueId = selectedQueueId;
                    }
                }
                $('#tcDialog .confirm', container).addClass('loading');
                sendTCRequest(sendInfo).then(() => {
                    $('#tcDialog .confirm', container).removeClass('loading');
                    c.handlingTC = false;
                });
            });

            $('.closeSessionDialog .chat-dialog-close', container).click(function () {
                $('.closeSessionDialog', container).hide();
            });

            //个性配置
            $('#mmpop_system_menu .cog', container).click(function () {
                $('.configDialog', container).show().css({
                    "paddingTop": ($(container).height() - $('.configDialog .chat-dialog-content', container).height()) / 2
                });
            });
            $('.leftPanelColor', container).change(function () {
                $('.left_panel', container).css('background-color', $(this).val());
                $.cookie('chat.leftpanel.bgcolor', $(this).val(), {
                    expires: 365
                });
            });
            //注册"聊天面板放到左侧"的单选框事件，重新构建chatPanel
            $('.configDialog .swapRL', container).change(function () {
                var swapRL = $(this).is(':checked') ? 'right' : 'left';
                $.cookie('chat.swapRL', swapRL, {
                    expires: 365
                });
                $E.openChatPanel(false, true);
            });
            //注册"是否开启输入联想"单选框事件
            $('.configDialog .suggestionEnabled', container).change(function () {
                customSuggestionEnabled = $(this).is(':checked');
                $.cookie('chat.suggestionEnabled', customSuggestionEnabled, {
                    expires: 365
                });
            });
            //注册"是否开启新消息置顶"单选框
            $('.configDialog input[name=topSessionOnNewMessage]', container).change(function () {
                topSessionOnNewMessage = $('.configDialog input[name=topSessionOnNewMessage]:checked').val();
                $.cookie('chat.topSessionOnNewMessage', topSessionOnNewMessage, {
                    expires: 365
                });
            });
            //注册"是否开启敏感词提示"单选框
            $('.configDialog .dirtyWordsScanEnabled', container).change(function () {
                dirtyWordsScanEnabled = $(this).is(':checked');
                $.cookie('chat.dirtyWordsScanEnabled', dirtyWordsScanEnabled, {
                    expires: 365
                });
                if (dirtyWordsScanEnabled) {
                    //加载脏词库
                    callService({
                        data: {
                            requestType: 'loadDirtyWords'
                        }
                    }).done(function (data) {
                        if (data.status === "success") {
                            c.dirtyWords = data.dirtyWords;
                        }
                    }).fail(function () {
                        $F.err('Chat - loadDirtyWords', i18n.error.loadDirtywordsFailed);
                    });
                }
            });

            //注册"是否开启辅助机器人自动回复"单选框
            $('.configDialog .robotAutoAnswerEnabled', container).change(function () {
                robotAutoAnswerEnabled = $(this).is(':checked');
                $.cookie('chat.robotAutoAnswerEnabled', robotAutoAnswerEnabled, {
                    expires: 365
                });
            });

            //注册"是否开启辅助机器人自动回复"单选框
            $('.configDialog .translateAutoEnabled', container).change(function () {
                translateAutoEnabled = $(this).is(':checked');
                if (!translateAutoEnabled) {
                    Object.keys(sessionsMap).forEach(function (key) {
                        setTranslateLanguage(sessionsMap[key].id, '', '')
                    });
                }
                $.cookie('chat.translateAutoEnabled', translateAutoEnabled, {
                    expires: 365
                });
            });
            //注册"网聊新消息通知是否开启声音"单选框
            $('.configDialog .newMassageSoundSwitch', container).change(function () {
                newMassageSoundEnabled = $(this).is(':checked');
                $.cookie('chat.newMassageSoundEnabled', newMassageSoundEnabled, {
                    expires: 365
                });
            });


            //注册"是否直接推送满意度"单选框
            $('.configDialog .pushRatingDirectly', container).change(function () {
                pushRatingDirectly = $(this).is(':checked');
                $.cookie('chat.pushRatingDirectly', pushRatingDirectly, {
                    expires: 365
                });
            });

            //注册"翻译目标语言"下拉框
            $('.configDialog .transToConfig', container).change(function () {
                $.cookie('chat.translateTo', $(this).val(), {
                    expires: 365
                });
                if (translateAutoEnabled) {
                    let agentLanguage = $(this).val();
                    //对所接收到的语言进行设置
                    Object.keys(sessionsMap).forEach(function (key) {
                        setTranslateLanguage(sessionsMap[key].id, agentLanguage, sessionsMap[key].languageTo)
                    });
                }
            });


            $('.configDialog .chat-dialog-close', container).click(function () {
                $('.configDialog', container).hide();
            });


            //退出
            $('#mmpop_system_menu .sign-out', container).click(function () {
                var findActiveSession = false;
                $.each(sessionsMap, function (key, s) {
                    if (s.permFlag != 1 && s.active) {
                        findActiveSession = true;
                        return false;
                    }
                });
                if (findActiveSession) {
                    return $F.alert(i18n.error.closeSessionsBeforeLoggedOut);
                }
                if (userStatusTimer)
                    clearTimeout(userStatusTimer);
                c.logoutAndClose();
            });

            $('.requestDialog .chat-dialog-close', container).click(function () {
                $('.requestDialog', container).hide();
            });

            $('.message_preview_btn', container).click(function () {
                var msg = $('.control_panel .content #edit-area', container).html();// 可能需要改成text()，albert说这里用html会出现转义，可能造成消息发不出去
                if (msg) {
                    c.previewFormattedMessage(msg);
                }
            });
            $('.messagePreviewDialog .confirm', container).click(function () {
                $('.messagePreviewDialog', container).hide();
                var $this = $(this);
                sendMessage($this.data('msg'), $this.data('sessionId'), undefined, undefined, function () {
                    $('.control_panel .content #edit-area', container).html("");
                });
            });
            $('.messagePreviewDialog .chat-dialog-close', container).click(function () {
                $('.messagePreviewDialog', container).hide();
            });

            $('.session_more_menu .stick', container).click(function () {
                let sessionId = $('.session_more_menu', container).data('sessionId');
                let target = $('#sessionTab_' + sessionId, container);
                if (target.hasClass('top')) {
                    if (target.hasClass('closed')) {
                        $('.session_list .chat_item', container).last().after(target);
                    } else {
                        if ($('.session_list .chat_item:not(.top)', container).length > 0) {
                            $('.session_list .chat_item:not(.top)', container).first().before(target);
                        } else {
                            $('.session_list .chat_item.top', container).last().after(target);
                        }
                    }
                    $(target).removeClass('top');
                } else {
                    if ($('.session_list .chat_item.top.closed', container).length > 0) {
                        if (target.hasClass('closed')) {
                            $('.session_list .chat_item.top.closed', container).last().after(target);
                        } else {
                            $('.session_list .chat_item.top.closed', container).first().before(target);
                        }
                    } else if ($('.session_list .chat_item.top', container).length > 0) {
                        $('.session_list .chat_item.top', container).last().after(target);
                    } else {
                        $('.session_list .chat_item', container).first().before(target);
                    }
                    $(target).addClass('top');
                }
            });

            $('.session_more_menu .lock', container).click(function () {
                let sessionId = $('.session_more_menu', container).data('sessionId');
                let target = $('#sessionTab_' + sessionId, container);
                if (target.hasClass('locked')) {
                    $(target).removeClass('locked');
                    sessionsMap["session" + sessionId].locked = false;
                } else {
                    $(target).addClass('locked');
                    sessionsMap["session" + sessionId].locked = true;
                }
            });

            /**
             * 加载cookie配置
             */
              // 加载左侧chatItem背景色
            var leftPanelBgColor = $.cookie("chat.leftpanel.bgcolor");
            if ($F.isColorStr(leftPanelBgColor)) {
                $('.left_panel', container).css('background-color', leftPanelBgColor);
            }
            //加载显示在左还是右
            if ($.cookie('chat.swapRL') === 'right') {
                $('.configDialog .swapRL', container).prop('checked', true);
            }
            //加载是否开启建议提示
            if (!suggestionSearchEnabled) {// 如果系统配置就不开启建议搜索，则不显示个性配置中的是否开启
                $('.configDialog .suggestionEnabledContainer', container).hide();
            } else {// 如果系统开启，则考虑cookie，来设置自定义是否开启
                customSuggestionEnabled = $.cookie('chat.suggestionEnabled') === 'true';
                $('.configDialog .suggestionEnabled', container).prop('checked', customSuggestionEnabled);
            }
            //加载是否新消息来置顶
            topSessionOnNewMessage = $.cookie('chat.topSessionOnNewMessage');
            $('.configDialog input[name=topSessionOnNewMessage][value=' + topSessionOnNewMessage + ']', container).attr('checked', 'checked');
            //加载敏感词过滤
            dirtyWordsScanEnabled = $.cookie('chat.dirtyWordsScanEnabled') === 'true';
            $('.configDialog .dirtyWordsScanEnabled', container).prop('checked', dirtyWordsScanEnabled);
            //加载辅助机器人自动应答
            robotAutoAnswerEnabled = $.cookie('chat.robotAutoAnswerEnabled') === 'true';
            $('.configDialog .robotAutoAnswerEnabled', container).prop('checked', robotAutoAnswerEnabled);
            //加载自动翻译的配置
            translateAutoEnabled = $.cookie('chat.translateAutoEnabled') === 'true';
            $('.configDialog .translateAutoEnabled', container).prop('checked', translateAutoEnabled);
            //加载来新消息是否声音提醒
            newMassageSoundEnabled = $.cookie('chat.newMassageSoundEnabled') === 'true';
            $('.configDialog .newMassageSoundSwitch', container).prop('checked', newMassageSoundEnabled);
            //加载是否开启直接推送满意度
            pushRatingDirectly = $.cookie('chat.pushRatingDirectly') === 'true';
            $('.configDialog .pushRatingDirectly', container).prop('checked', pushRatingDirectly);
            $('.configDialog .transToConfig', container).val($.cookie('chat.translateTo') || 'zh');

            //初始化请求tabs
            requestTabs = $('.requestDialog .requestTabs', container).tabs({
                heightStyle: "fill"
            });

            //事件注册
            /**
             * 添加消息到输入框, 可以让动态页面去管理预存消息，通过这个事件发送给chat模块
             */
            project.events.register($CONST.ChatEvent.ADD_MESSAGE_TO_TEXTAREA, 'chat', function (data) {
                var content = data.content;
                if (content) {
                    var curSession = sessionsMap["session" + currentSessionId];
                    if (curSession && curSession.active) {
                        if (data.raw) {
                            $('.control_panel .content #edit-area', container).text(content);
                        } else {
                            if (!data.nobr)
                                content = content.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\r/g, '<br/>');
                            $('.control_panel .content #edit-area', container).html(content);
                        }
                    }
                }
            });
            /**
             * 关闭会话消息，收到此消息后，关闭对应会话
             */
            project.events.register($CONST.ChatEvent.CLOSE_SESSION, 'chat', function (data) {
                var sessionId = parseInt(data.sessionId);
                var comments = data.comments || '';
                var callNatures = data.callNatures || '';
                removeTabAndSession(sessionId, callNatures, comments);
            });

            /**
             * 结束会话消息，收到此消息后，结束对应会话，但是不会关闭tab
             */
            project.events.register($CONST.ChatEvent.END_SESSION || 'END_SESSION', 'ChatMonitor', function (data) {
                var sessionId = parseInt(data.sessionId);
                var comments = data.comments || '';
                var callNatures = data.callNatures || '';
                endSession(sessionId, callNatures, comments);
            });

            /**
             * 改变客户，动态页面可以发出这个消息来改变当前聊天客户
             */
            project.events.register($CONST.ChatEvent.CHANGE_CLIENT, 'ChatMonitor', function (data) {
                var sessionId = data.sessionId;
                var clientId = data.clientId;
                var session = sessionsMap["session" + sessionId];
                if (session) {
                    //调用changeCustomer接口，修改会话中的客户
                    callService({
                        data: {
                            requestType: 'changeCustomer',
                            sessionId: sessionId,
                            customerGuid: clientId
                        }
                    }).done(function (data) {
                        if (data.status === "success") {
                            updateClientForSession(session, clientId, data.customerName);
                        } else {
                            $F.err('Chat - changeCustomer', 'Change customer failed: ' + clientId);
                        }
                    }).fail(function () {
                        $F.err('Chat - changeCustomer', 'Change customer failed: ' + clientId);
                    });
                } else {
                    $F.log('Chat - CHANGE_CLIENT', 'No session found: ' + sessionId);
                }
            });

            /**
             * 更新某个会话的客户的标签
             */
            project.events.register($CONST.ChatEvent.UPDATE_CLIENT_TAGS, 'ChatMonitor', function (data) {
                var chatItem = $('#sessionTab_' + data.sessionId, container);
                if (chatItem.length > 0 && data.tags) {
                    $('.tags', chatItem).empty();
                    var tagsContainer = $('.tags', chatItem);
                    $.each(data.tags, function (i, t) {
                        tagsContainer.append('<span style="background-color:' + t.bgColor + ';color:' + t.color + '">' + t.comments + '</span>');
                    });
                }
            });

            /**
             * 添加自定义信息到客户的tab上
             */
            project.events.register($CONST.ChatEvent.ADD_CUSTOMINFO_ON_CHATITEM, 'ChatMonitor', function (data) {
                var chatItem = $('#sessionTab_' + data.sessionId, container);
                if (chatItem.length > 0 && data.customInfo) {
                    $('.customInfo', chatItem).remove();
                    var customInfoContainer = $('<div class="customInfo">');
                    customInfoContainer.append(data.customInfo);
                    chatItem.append(customInfoContainer);
                }
            });

            /**
             * 更新某个会话的客户的评级
             */
            project.events.register($CONST.ChatEvent.UPDATE_CLIENT_RATE, 'ChatMonitor', function (data) {
                var chatItem = $('#sessionTab_' + data.sessionId, container);
                if (chatItem.length > 0 && !isNaN(data.rating)) {
                    $('.rate', chatItem).rateYo("rating", data.rating);
                }
            });

            /**
             * 拉黑某个客户，需要传递sessionId
             */
            project.events.register($CONST.ChatEvent.BLOCK_USER, 'ChatMonitor', function (data) {
                callService({
                    data: {
                        requestType: 'blockUser',
                        sessionId: data.sessionId,
                        comment: data.comment
                    }
                }).done(function (data) {
                    if (data.status === 'success') {
                        $F.log('Chat - blockUser', i18n.blockUser + ' [' + data.clientId + ' ]' + i18n.success);
                        $F.notify(i18n.blockUser + ' [' + data.clientId + '] ' + i18n.success);
                    } else {
                        $F.err('Chat - blockUser', i18n.error.blockUserFailed, data);
                    }
                }).fail(function () {
                    $F.err('Chat - blockUser', i18n.error.blockUserFailed);
                });
            });

            /**
             * 直接发送消息, 如果传递noticeType，则把消息作为通知类型消息发送，不然则作为普通消息发送
             * {
            		sessionId: 1,  	//会话id
            		content: '消息内容', //消息内容
            		noticeType: 99, 	//通知消息类型(可选)
            		success: function(data){ //发送成功回调
            			console.log(data);
            		}
            	}
             */
            project.events.register($CONST.ChatEvent.SEND_MESSAGE, 'ChatMonitor', function (data) {
                $F.log('Chat - sendMessage', JSON.stringify(data));
                var session = sessionsMap["session" + data.sessionId];
                if (session && session.active) {
                    if (data.noticeType) {
                        callService({
                            data: {
                                requestType: 'send',
                                data: getPostNoticeMessageSentInfo(data.content, data.sessionId, data.noticeType, data.receiverId)
                            }
                        }).done(function (data) {
                            if (data.noticeType != NOTICE_TYPE.TYPING && data.noticeType != NOTICE_TYPE.CUSTOM) {
                                if (data.content) {
                                    if (data.sessionId == currentSessionId) {
                                        appendTextToDiv(formatFeedbackMessage(data.content));
                                    }
                                    addMessageToSession(data.sessionId, {
                                        id: "-1",
                                        name: null
                                    }, {
                                        text: formatFeedbackMessage(data.content),
                                        type: MESSAGE_TYPE.SYSTEM
                                    }, undefined);
                                }
                            }
                            if ($.isFunction(data.success)) {
                                data.success(data);
                            }
                        }).fail(function () {
                            $F.err('Chat -sendMessage', i18n.error.sendMessageFailed);
                        });
                    } else {
                        if (data.content) {// 通知类消息可以没有content，但是普通消息必须要有
                            data.content = data.content.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\r/g, '<br/>');
                            sendMessage(data.content, data.sessionId, data.content, data.extra, data.success);
                        }
                    }
                }
            });

            if (!project.chatSwitch) {
                project.chatSwitch = project.rightPanelSwitch;
            }
            //点击chat按钮删除提示数字
            project.chatSwitch.click(function (e) {
                e.preventDefault();
                $('i.web_wechat_reddot_middle', project.chatSwitch).remove();
            });


            //初始数据加载
            async.series([
                function (callback) {
                    if (enableCrossWorkgroupTransfer) {
                        $('#tcDialog .chat-workgroup-select', container).show();
                    }
                    // 获取所有工作组
                    callService({
                        data: {
                            requestType: 'getAllWorkgroupsAndQueues',
                            from: 'h5',
                            token: c.project.token
                        }
                    }).done(function (data) {
                        if (data.status === "success") {
                            c.workgroups = data.workgroups;
                            $.each(c.workgroups, function (i, workgroup) {
                                $('#tcDialog .chat-workgroup-select', container).append('<option value=' + workgroup.id + '>' + workgroup.name + '</option>');
                            });
                            $('#tcDialog .chat-workgroup-select', container).change(function () {
                                $('#tcDialog .chat-queue-select', container).empty();
                                var workgroupId = parseInt(this.value);
                                var selectedWorkgroup = c.workgroups.filter(function (w) {
                                    return w.id === workgroupId;
                                });
                                if (selectedWorkgroup && selectedWorkgroup.length >= 1) {
                                    selectedWorkgroup = selectedWorkgroup[0];
                                    if (currentTIR !== 'agentTransferToQueue') {
                                        $('#tcDialog .chat-queue-select', container).append('<option value="-1">' + i18n.all + '</option>');
                                    }
                                    $.each(selectedWorkgroup.queues, function (i, queue) {
                                        $('#tcDialog .chat-queue-select', container).append('<option value=' + queue.id + '>' + queue.name + '</option>');
                                    });
                                    $('#tcDialog .chat-queue-select', container).change();
                                }
                            });
                            $('#tcDialog .chat-queue-select', container).change(function () {
                                getAgentListByQueueId($('#tcDialog .chat-workgroup-select', container).val(), $(this).find('option:selected').val());
                            });

                            $('#tcDialog .agentname-input', container).keyup(function () {
                                var filterName = $(this).val();
                                var filteredAgentList = c.agentList.filter(function (agent) {
                                    var agentName = agent.name || agent.firstName;
                                    return agentName.indexOf(filterName) > -1;
                                });
                                setupAgentsForTC($('#tcDialog .contacts', container), filteredAgentList, filterName);
                            });
                        } else {
                            $F.err('ChatMonitor - getAllWorkgroupsAndQueues', i18n.error.loadQueueAndWorkgroupFailed, data);
                        }
                        callback(null, 'workgroups');
                    }).fail(function () {
                        $F.err('ChatMonitor - getAllWorkgroupsAndQueues', i18n.error.loadQueueAndWorkgroupFailed);
                        callback("get workgroups ajax failed", 'workgroups');
                    });
                },
                //get config
                function (callback) {
                    //获取配置信息
                    callService({
                        data: {
                            requestType: "getAgentConfigurations",
                            from: 'h5',
                            token: c.project.token
                        }
                    }).done(function (data) {
                        if (data && data.status === "success") {
                            c.configs = data.agentConfigs;
                            $F.log('ChatMonitor - init', 'agentConfigurations: ' + JSON.stringify(c.configs));

                            if (!c.configs.isAgentInWorkgroup) {
                                $F.alert(i18n.error.notAssignedAQueue);
                            }
                            //如果存在持久会话，则直接显示相关会话
                            var permSessions = c.configs.permSessions;
                            if (permSessions && permSessions.length > 0) {
                                $.each(permSessions, function (i, session) {
                                    var sessionId = session.id;
                                    $F.log("ChatMonitor - perm session", "Load permanent session " + sessionId);
                                    var client = session.client;
                                    var newSession = createSession(sessionId, client, -1, '', {});
                                    newSession.permFlag = 1;
                                    sessionsMap["session" + sessionId] = newSession;
                                    sessionIdsArr[sessionIdsArr.length] = sessionId;
                                    lastCreatedSessionId = "session" + sessionId;
                                    setupClientDisplayName(client);
                                    setupClientIcon(client);
                                });
                            }
                            c.configs.fileAcceptExtensions = c.configs.fileAcceptExtensions ? c.configs.fileAcceptExtensions.split(',') : [];

                            //注册划词搜索
                            if (c.configs.moveSearchCannedMessageEnabled) {
                                $('#agentResponseDiv', container).on('mouseup', function () {
                                    var selectionText = Tools.getSelectionText();
                                    if (selectionText) {
                                        notifyProjectEvent('MOVE_SEARCH', {
                                            sessionId: currentSessionId,
                                            text: selectionText
                                        });
                                    }
                                });
                            }

                            //是否允许坐席修改状态
                            if (c.configs.allowAgentStatusChange === 'false') {
                                $('#mmpop_system_menu .status-change', container).hide();
                            }

                            if (c.configs.agentRealtimeQueueMonitorEnable) {
                                $('.stat_info', container).show();
                            }
                        } else {
                            $F.err('ChatMonitor - getAgentConfigurations', 'Get configuration failed', data);
                        }
                        callback(null, "config");
                    }).fail(function (e) {
                        $F.err('ChatMonitor - getAgentConfigurations', 'Get configuration failed', e);
                        callback("get config ajax failed", "config");
                    });


                    if (dirtyWordsScanEnabled) {
                        //加载脏词库
                        callService({
                            data: {
                                requestType: 'loadDirtyWords'
                            }
                        }).done(function (data) {
                            if (data.status === "success") {
                                c.dirtyWords = data.dirtyWords;
                            } else {
                                $F.err('ChatMonitor - loadDirtyWords', i18n.error.loadDirtywordsFailed);
                            }
                        }).fail(function () {
                            $F.err('ChatMonitor - loadDirtyWords', i18n.error.loadDirtywordsFailed);
                        });
                    }
                    if (highlightWordsScanEnable) {
                        //加载关键词词库
                        callService({
                            data: {
                                requestType: 'loadHighlightWords'
                            }
                        }).done(function (data) {
                            if (data.status === "success") {
                                c.highlightWords = data.highlightWords;
                            } else {
                                $F.err('ChatMonitor - loadHighlightWords', i18n.error.loadHighlightWordsFailed);
                            }
                        }).fail(function () {
                            $F.err('ChatMonitor - loadHighlightWords', i18n.error.loadHighlightWordsFailed);
                        });
                    }
                    //加载禁用词词库
                    callService({
                        data: {
                            requestType: 'loadForbidWords'
                        }
                    }).done(function (data) {
                        if (data.status === "success") {
                            c.forbidWords = data.forbidWords;
                        } else {
                            $F.err('Chat - loadForbidWords', i18n.error.loadForbidWordsFailed);
                        }
                    }).fail(function () {
                        $F.err('Chat - loadForbidWords', i18n.error.loadForbidWordsFailed);
                    });


                    if (!disableSplitter) {
                        //创建聊天item列表与详情的左右splitter
                        $('.ChatMonitor', container).wisSplitter({
                            direct: 'h',
                            cookie: 'ChatMonitor.chatSplitter',
                            fixedSize: 211,
                            minSize: 190,
                            maxSize: 300
                        });

                        //创建聊天消息历史和输入框的上下splitter
                        $('.session_content_container', container).wisSplitter({
                            direct: 'v',
                            cookie: 'ChatMonitor.contentSplitter',
                            minSize: 110,
                            maxSize: 400,
                            fixedSize: 180,
                            fixed: 1
                        });
                    }
                },
                //获取到监控会话的id并加载会话内容
                function (callback) {
                    if (parameters.sessionId) {
                        searchSessionMessage(callback)
                    } else if (parameters.staffId) {
                        searchStaffSessions(callback)
                    }
                }
            ], function (err, results) {
                $F.busyHide(busyId);
                if (!err) {
                    $F.log('ChatMonitor - init', 'Init ChatMonitor successful');
                } else {
                    $F.err('ChatMonitor - init', 'Init ChatMonitor failed: ' + err);
                }
            });
        };

        function searchStaffSessions(callback = null, staffId = undefined, refresh = false) {
            callService({
                url: "admin/sessionListForMonitor",
                data: {
                    action: "staffSessions",
                    staffId: staffId || parameters.staffId
                }
            }).done(function (data) {
                // FIXME here
                $('.chat-monitor .session_list').show()
                if (data.code === 200) {
                    if (refresh) {
                        $('.session_list .chat_item').remove()
                        $('.chat-monitor #agentResponseDiv')[0].innerText = null
                        $('.chat-monitor .session_hd .session_last').text('')
                        $('.chat-monitor .session_hd .session_btn_container').hide()
                    }
                    const findSessions = data.data.sessions || []
                    if (!findSessions.length) {
                        document.querySelector('.chat-monitor .session_list').innerHTML = `<div class="empty">当前没有可监控的坐席</div>`
                    } else {
                        $('.chat-monitor .session_list .list_header .cur_staff_id').text('id: ' + parameters.staffId)
                        findSessions.forEach((session) => {
                            $('.chat-monitor .session_list .list_header .cur_staff_name').text(session.agents[parameters.staffId].name)
                            sessionsMap['session' + session.id] = session;
                            createNewTab('sessionTab_' + session.id, session.client)
                        })
                        // console.log(data)
                    }
                    callback && callback(null, "init");
                } else {
                    $F.alert('查询出错');
                    console.log('查询出错', data)
                    callback && callback(null, "init");
                }
            }).fail(function (xhr) {
                $F.alert('查询出错');
                callback && callback("查询报错" + parameters.staffId);
            });
        }

        function searchSessionMessage(callback = null, click = false, id = undefined) {
            callService({
                url: "admin/sessionListForMonitor",
                data: {
                    action: "querySessionTranscript",
                    sessionId: id ? id : parameters.sessionId,
                    from: 'h5',
                    token: c.project.token,
                    ds: $E.dataService.key
                }
            }).done(function (data) {
                if (data.code === 200) {
                    data = data.data;
                    let session = data.session, sessionVo = data.sessionVO, client = data.client,
                      agent = data.agent
                      , sessionId = session.id, queueId = session.queueId, queueName = '';
                    c.staff = agent;
                    currentStaffId = Object.keys(session.agents).find((item)=>{return !item.startsWith('BOT')});
                    // currentStaffId = Object.keys(session.agents)[0];
                    if (callback) {
                        let newSession = createSession(sessionId, client, queueId, queueName)
                        sessionsMap["session" + sessionId] = newSession;
                        if (takeOverArray.indexOf(currentSessionId) !== -1) {
                            $('.invite, .transfer, .transferToQueue, .close-session', container).show();
                            $('.take-over', container).hide()
                        } else {
                            $('.invite, .transfer, .transferToQueue, .close-session', container).hide();
                            $('.take-over', container).show()
                        }
                    }
                    // $('.chat-monitor #agentResponseDiv')[0].innerText = null
                    if (!click && sessionVo.newMessages.length < allMessages.length) {
                        refreshFlag = true
                        console.log('网聊监控页面信息需刷新')
                    } else if (click || (sessionVo.newMessages.length === allMessages.length && refreshFlag)) {
                        $('.chat-monitor #agentResponseDiv')[0].innerText = null
                        $.each(sessionVo.newMessages, function (i) {
                            var displayMessage = getDisplayMessage(sessionVo.newMessages[i], session);
                            appendTextToDiv(displayMessage);
                        })
                        refreshFlag = false
                    } else if (sessionVo.newMessages.length > allMessages.length) {
                        const newMsg = sessionVo.newMessages.slice(allMessages.length)
                        $.each(newMsg, function (i) {
                            var displayMessage = getDisplayMessage(newMsg[i], session);
                            appendTextToDiv(displayMessage);
                        })
                    }
                    if (session.endTime == -1) {
                        enableSession(sessionId);
                    } else {
                        disableSession(sessionId);
                        // searchSessionMessage(null, true, currentSessionId)
                    }
                    allMessages = sessionVo.newMessages
                    if (searchMessagePull) {
                        clearTimeout(searchMessagePull)
                    }
                    if (chatMonitorPullTime && chatMonitorPull) {
                        searchMessagePull = setTimeout(()=>{
                            searchSessionMessage(null, false, currentSessionId)
                        }, chatMonitorPullTime * 1000)
                    }
                    if (!session.closed && session.startTime) {
                        $('.chat-monitor .session_hd .session_last', container).html(i18n.lasting + ':' + Tools.getFormattedLasting(new Date().valueOf() - session.startTime));
                    }
                    callback && callback(null, "init");
                } else {
                    callback && callback(data.message);
                }
            }).fail(function (xhr) {
                $F.alert(i18n.error.loggedInChatFailed);
                callback && callback("login ajax failed: " + xhr.status + ' ' + xhr.statusText, "login");
            });
        }


        //设置过了CKEDITOR.disableAutoInline = true; 就不需要单独先初始化CKEditor了
        H5Utils.loadPlugin({
            name: 'ChatMonitor',
            container: container,
            html: 'chatMonitor/index.' + ($E.lang === 'zh_CN' ? '' : $E.lang + '.') + 'html',
            css: 'chatMonitor/default.css',
            done: function (dom) {
                c.pluginDom = dom;
                init();
            }
        });

        return c;
    };

    ChatMonitor.prototype = {

        /**
         * 重新激活插件，刷新插件数据
         * @method active
         * @param parameter {any} 插件入参
         */
        active: function (parameter) {
            if (this.parameter == parameter)
                return;
            this.parameter = parameter;
        },

        close: function () {
            $F.log('ChatMonitor', i18n.closeChat);
            chatMonitorPull = false
            this.logoutAndClose();
        }
    };

    // 老ngs兼容處理
    function compatibleOldNgsFunctions(project) {
        if ($E.rightPanel instanceof Function) {
            $E.openChatPanel = $E.rightPanel;
        }
        if (project.rightPanelSwitch) {
            project.chatSwitch = project.rightPanelSwitch;
        }
    }

    return {
        avaliable: function (project, addin, addinParam, parameter) {
            return {
                code: 1,
                message: 'OK'
            }
        },

        close: function () {
            $F.log('ChatMonitor - close', 'ChatMonitor page closed ...');
        },

        newInstance: function (project, container, addinParam, arguments4, parameters) {
            return new ChatMonitor(project, container, parameters);
        },

        destroy: function () {

        }
    }
});